package com.dingreading.cloud.soms.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dingreading.cloud.common.base.R;
import com.dingreading.cloud.common.dto.LoginDataDto;
import com.dingreading.cloud.common.util.*;
import com.dingreading.cloud.common.util.excel.ExcelHandler;
import com.dingreading.cloud.soms.dto.*;
import com.dingreading.cloud.soms.entity.*;
import com.dingreading.cloud.soms.service.*;
import com.dingreading.cloud.soms.util.CmorderUtil;
import com.dingreading.cloud.soms.util.FollowUtil;
import com.dingreading.cloud.soms.util.LoginInfoUtil;
import com.dingreading.cloud.soms.util.OrderAmountSplitUtil;
import com.dingreading.cloud.soms.util.redis.RedisService;
import com.mybatisflex.core.paginate.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@RestController
@RequestMapping(value = "/front/cmOrder")
@Api(tags = "门店-会员服务订单管理(最新)")
public class FrontCmOrderController {

    @Resource
    protected StoreProjectsService projectsService;
    @Resource
    private CmordersService cmordersService;
    @Resource
    private CmservicesService cmservicesService;
    @Resource
    private CmpaypicsService cmpaypicsService;
    @Resource
    private StaffService staffService;
    @Resource
    private MembersService membersService;
    @Resource
    private MemberFollowService memberFollowService;
    @Resource
    private ServiceStatusLogsService serviceStatusLogsService;
    @Resource
    private StoreProjectsService storeProjectsService;
    @Resource
    private StoreProductsService storeProductsService;
    @Resource
    private StoreProductLogsService productLogsService;
    @Resource
    private OrderStatusLogsService orderStatusLogsService;
    @Resource
    private CmorderApplyService cmorderApplyService;
    @Resource
    private CmorderApplyImgService cmorderApplyImgService;
    @Resource
    private CmorderApplyLogService cmorderApplyLogService;
    @Resource
    private ReceiptRegisterService receiptRegisterService;
    @Resource
    private ReceiptRegisterImgService receiptRegisterImgService;
    @Resource
    private StoresService storesService;
    @Resource
    private RedisService redisService;
    @Resource
    private OrderAmountSplitUtil orderAmountSplitUtil;
    @Resource
    private SubjectsService subjectsService;
    @Resource
    private CmactivationCodeService cmactivationCodeService;

    private final int noCardStatus = EnumType.ServiceStatus.NO_CARD.getStatus();
    private final int openCardStatus = EnumType.ServiceStatus.OPEN_CARD.getStatus();
    private final int pauseCardStatus = EnumType.ServiceStatus.PAUSE_CARD.getStatus();
    private final int refundStatus = EnumType.ServiceStatus.REFUND.getStatus();
    private final String refundName = EnumType.ServiceStatus.REFUND.getName();
    private final int invalidStatus = EnumType.ServiceStatus.INVALID.getStatus();
    private final String invalidName = EnumType.ServiceStatus.INVALID.getName();
    private final int changeStatus = EnumType.ServiceStatus.CHANGE.getStatus();
    private final String changeName = EnumType.ServiceStatus.CHANGE.getName();


    @ApiOperation(value = "分页列表")
    @PostMapping(value = "/pageList")
    public R<Object> pageList(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "分页公共类") PageUtil pageUtil,
            @ApiParam(value = "会员uid") @RequestParam(value = "memberUid", required = false) String memberUid,
            @ApiParam(value = "订单号/会员姓名/合同号") @RequestParam(value = "keyword", required = false) String keyword,
            @ApiParam(value = "收入类型") @RequestParam(value = "orderType", required = false) String orderType,
            @ApiParam(value = "收款开始日期") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "收款结束日期") @RequestParam(value = "endDate", required = false) String endDate,
            @ApiParam(value = "财务审批状态 0.待审批 1.通过 -1.退回") @RequestParam(value = "status", required = false) Integer status
    ) {
        Page<CmorderDto> page = cmordersService.storePage(
                pageUtil, storeUid, memberUid, keyword, orderType, beginDate, endDate, status
        );

        List<CmorderDto> list = page.getRecords();
        // 获取开卡、未开卡、暂停状态的服务列表
        if (CollectionUtils.isNotEmpty(list))
            CmorderUtil.getServiceListByOrderCode(storeUid, list);

        PageBeanDto data = new PageBeanDto();
        data.setTotal(page.getTotalRow());
        data.setList(list);
        return R.ok(data);
    }


    @ApiOperation(value = "获取会员的服务订单列表")
    @PostMapping(value = "/getMemberOrders", produces = "application/json; charset=UTF-8")
    public R<Object> getMemberOrders(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "分页公共类") PageUtil pageUtil,
            @ApiParam(value = "会员uid") @RequestParam(value = "memberUid") String memberUid
    ) {
        Page<CmorderDto> page = cmordersService.storePage(
                pageUtil, storeUid, memberUid, null, null, null, null, null
        );

        List<CmorderDto> list = page.getRecords();

        // 获取开卡、未开卡、暂停状态的服务列表
        if (CollectionUtils.isNotEmpty(list))
            CmorderUtil.getServiceListByOrderCode(storeUid, list);

        PageBeanDto data = new PageBeanDto();
        data.setTotal(page.getTotalRow());
        data.setList(list);
        return R.ok(data);
    }


    @ApiOperation(value = "获取会员的服务项目列表")
    @PostMapping(value = "/getMemberServices", produces = "application/json; charset=UTF-8")
    public R<Object> getMemberServices(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "分页公共类") PageUtil pageUtil,
            @ApiParam(value = "会员uid") @RequestParam(value = "memberUid") String memberUid
    ) {
        Page<CmservicesDto> page = cmservicesService.pageList(pageUtil, storeUid, memberUid, null);

        List<CmservicesDto> list = page.getRecords();
        if (CollectionUtils.isNotEmpty(list)) {
            // 已开卡且可排活动的服务uid集合，获取消耗数量
            Map<String, Long> consumeMap = CmorderUtil.getConsumeLessonMapByDto(list);
            // 服务获取以活动次数，状态名称修改
            CmorderUtil.setUseLessonCntAndStatusName(list, consumeMap);
        }

        PageBeanDto data = new PageBeanDto();
        data.setTotal(page.getTotalRow());
        data.setList(page.getRecords());
        return R.ok(data);
    }

    @Transactional(rollbackFor = DescribeException.class)
    @ApiOperation(value = "创建/编辑会员的服务订单")
    @PostMapping(value = "/newBean", produces = "application/json; charset=UTF-8")
    public R<Object> newBean(
            HttpServletRequest request,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "收入类型 体验会员:EXP，正式会员新签:NEW，续费:RENEW，拓科:EXT，订金:EMD，赠送:GIFT") @RequestParam(value = "orderType") String orderType,
            @ApiParam(value = "服务json [{uid:'',isGift:0,projectUid:'',productUid:'',productLogUid:'',serviceDays:0,totalLessons:0,cycleName:'',pkgUid:''}]")
            @RequestParam(value = "serviceJson", required = false) String serviceJson,
            @ApiParam(value = "会员uid") @RequestParam(value = "memberUid") String memberUid,
            @ApiParam(value = "收款金额") @RequestParam(value = "orderAmount") Double orderAmount,
            @ApiParam(value = "收款日期 yyyy-MM-dd") @RequestParam(value = "orderDate") String orderDate,
            @ApiParam(value = "签单人uid") @RequestParam(value = "saleStaffUid") String saleStaffUid,
            @ApiParam(value = "签单人姓名") @RequestParam(value = "saleStaffFullName") String saleStaffFullName,
            @ApiParam(value = "服务订单编号") @RequestParam(value = "orderCode", required = false) String orderCode,
            @ApiParam(value = "合同编号") @RequestParam(value = "contractCode", required = false) String contractCode,
            @ApiParam(value = "礼品领取 已领取:1，未领取:0") @RequestParam(value = "giftGotten", required = false) String giftGotten,
            @ApiParam(value = "礼品备注") @RequestParam(value = "giftRemark", required = false) String giftRemark,
            @ApiParam(value = "备注") @RequestParam(value = "orderRemark", required = false) String orderRemark,
            @ApiParam(value = "收款方式 收款码:CCB_QR，开单工具:SALE_TOOL，现金:CASH，银行转账:BANK，收银机/POS机:POS")
            @RequestParam(value = "payChannelCode", required = false) String payChannelCode,
            @ApiParam(value = "收款登记uid") @RequestParam(value = "receiptUid", required = false) String receiptUid,
            @ApiParam(value = "付款截图json [{id:0,imgUrl:''}]") @RequestParam(value = "imgJson", required = false) String imgJson
    ) throws Exception {
        R<Object> r = LoginInfoUtil.getLoginDto(request);
        if (R.isError(r)) return r;
        LoginDataDto loginDto = (LoginDataDto) r.getData();

        boolean storeManager = AccountUtil.isManagerOrAdvisor(loginDto.getStoreRoles());
        if (!storeManager)
            return R.fail("不是店长或店助，不能操作");

        if (StringUtils.isBlank(orderType))
            return R.fail("请选择收入类型");
        if (null == orderAmount || orderAmount < 0)
            return R.fail("请填写正确的收款金额");
        if (StringUtils.isBlank(orderDate))
            return R.fail("请填写收款日期");
        if (StringUtils.isBlank(saleStaffUid) || StringUtils.isBlank(saleStaffFullName))
            return R.fail("请选择签单人或完善签单人的信息");

        // 是否订金订单
        boolean isEmd = orderType.equals(EnumType.OrderType.EMD.getType());
        List<Cmservices> serviceList = new ArrayList<>();
        if (isEmd) {
            if (StringUtils.isNotBlank(serviceJson))
                return R.fail("收入类型是订金，不能添加服务或产品包");
        } else {
            if (StringUtils.isBlank(serviceJson))
                return R.fail("请添加服务或产品包");

            serviceList = JSONObject.parseArray(serviceJson, Cmservices.class);
            if (CollectionUtils.isEmpty(serviceList))
                return R.fail("服务信息转换失败");
        }

        List<Cmpaypics> payPicList = null;
        if (StringUtils.isNotBlank(imgJson)) {
            if (StringUtils.isBlank(payChannelCode))
                return R.fail("请选择收款方式");
            payPicList = JSONObject.parseArray(imgJson, Cmpaypics.class);
            if (CollectionUtils.isEmpty(payPicList))
                return R.fail("付款截图转换失败");
        } else {
            if (AccountUtil.isSelfStore(loginDto.getCurrentOperationType()) && orderAmount > 0)
                return R.fail("收款金额大于0，需上传付款截图");
        }
        if (StringUtils.isNotBlank(receiptUid)) {
            ReceiptRegister receiptRegister = receiptRegisterService.getByUid(storeUid, receiptUid);
            if (receiptRegister == null)
                return R.fail("未查询到收款登记");
            if (StringUtils.isNotBlank(receiptRegister.getOrderCode()) && !receiptRegister.getOrderCode().equals(orderCode))
                return R.fail("收款登记已被绑定使用");
        }


        List<String> projectUids = new ArrayList<>();
        List<String> productUids = new ArrayList<>();
        List<String> productLogUids = new ArrayList<>();
        // 处理和验证要保存或编辑的服务信息
        if (!isEmd) {
            String dealServiceList = CmorderUtil.dealServiceList(projectUids, productUids, productLogUids, serviceList, orderType);
            if (StringUtils.isNotBlank(dealServiceList))
                return R.fail(dealServiceList);
        }

        Members members = membersService.getByUid(storeUid, memberUid);
        if (null == members)
            return R.fail("会员获取失败");
        String memberCorpUid = members.getCorpUid();

        Cmorders data = null;
        String followType = EnumType.Follow.NEW_ORDER.getType();
        String followTypeName = EnumType.Follow.NEW_ORDER.getName();
        if (StringUtils.isNotBlank(orderCode)) {
            data = cmordersService.getByOrderCode(storeUid, memberUid, orderCode);
            // 验证订单能否更新
            String msg = judgeUpdateCmorder(data, loginDto.getStoreRoles(), orderRemark);
            if (StringUtils.isNotBlank(msg))
                return R.fail(msg);

            followType = EnumType.Follow.UPDATE_ORDER.getType();
            followTypeName = EnumType.Follow.UPDATE_ORDER.getName();
        }

        // 验证签单人信息
        Staff saleStaff = staffService.getByUid(saleStaffUid);
        String msg = judgeSaleStaff(saleStaff);
        if (StringUtils.isNotBlank(msg))
            return R.fail(msg);

        Map<String, StoreProjects> projectMap = null;
        Map<String, StoreProducts> productMap = null;
        Map<String, StoreProductLogs> productLogMap = null;
        if (!isEmd) {
            List<StoreProjects> projectsList = storeProjectsService.listByUids(projectUids);
            if (CollectionUtils.isEmpty(projectsList))
                return R.fail("服务信息获取失败");
            projectMap = projectsList.stream().collect(Collectors.toMap(StoreProjects::getUid, Function.identity()));

            if (CollectionUtils.isNotEmpty(productUids)) {
                List<StoreProducts> productsList = storeProductsService.listByUids(productUids);
                if (CollectionUtils.isEmpty(productsList))
                    return R.fail("产品信息获取失败");
                productMap = productsList.stream().collect(Collectors.toMap(StoreProducts::getUid, Function.identity()));
            }

            if (CollectionUtils.isNotEmpty(productLogUids)) {
                List<StoreProductLogs> productLogsList = productLogsService.listByUids(productLogUids);
                if (CollectionUtils.isEmpty(productLogsList))
                    return R.fail("产品记录获取失败");
                productLogMap = productLogsList.stream().collect(Collectors.toMap(StoreProductLogs::getUid, Function.identity()));
            }
        }

        // 创建或更新订单信息
        data = CmorderUtil.newCmorder(
                data, memberCorpUid, storeUid, storeName, staffUid, staffName, memberUid, members.getMemberName(),
                saleStaffUid, saleStaffFullName, saleStaff.getPriPhone(), saleStaff.getPubPhone(), saleStaff.getNickName(),
                contractCode, orderType, orderAmount, DateUtil.parseDate(orderDate),
                giftGotten, giftRemark, orderRemark, payChannelCode, serviceList.size(), receiptUid
        );

        // 创建或更新服务信息
        msg = dealServiceList(
                memberCorpUid, storeUid, storeName, staffUid, staffName,
                serviceList, projectMap, productMap, productLogMap,
                memberUid, members.getMemberName(), data.getOrderCode(), orderType, isEmd
        );
        if (StringUtils.isNotBlank(msg))
            return R.fail(msg);

        // 创建或更新付款图片
        dealPayPicList(payPicList, data.getOrderCode(), staffUid);

        // 保存会员订单
        cmordersService.saveOrUpdate(data);

        Date followTime = DateUtil.getNowDatetime();
        //TODO 创建跟进记录
        MemberFollow follow = FollowUtil.newFollow(memberCorpUid, storeUid, storeName, staffUid, loginDto.getFullName(),
                members.getUid(), members.getMemberName(), followType, followTypeName,
                "订单号：" + data.getOrderCode(), data.getOrderCode(), followTime);
        memberFollowService.saveOrUpdate(follow);
        // 更新会员的最后跟进信息
        membersService.updateLastFollowInfo(storeUid, memberUid, follow.getUid(), followTime);

        // 绑定收款登记
        if (StringUtils.isNotBlank(receiptUid)) {
            boolean b = receiptRegisterService.updateStatus(storeUid, data.getOrderCode(), receiptUid, staffUid, staffName);
            if (b) {
                receiptRegisterImgService.updateInfo(storeUid, data.getOrderCode(), receiptUid, staffUid, staffName);
            }
        }

        // 订单金额拆分
        if (!isEmd) {
            msg = orderAmountSplitUtil.splitServiceAmount(data, NepUtil.nullToZero(data.getCarriedForwardAmount()), null);
            if (StringUtils.isNotBlank(msg))
                throw new DescribeException(msg);
        }

        // 清空门店缓存
        redisService.setNullLike(RedisParam.STORE_DATA + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_SERVICE + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_KINDS + storeUid);
        redisService.setNullLike(RedisParam.STORE_MEMBERS + storeUid);
        return R.ok();
    }


    @ApiOperation(value = "获取服务订单信息")
    @PostMapping(value = "/getBean", produces = "application/json; charset=UTF-8")
    public R<Object> getBean(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "会员uid") @RequestParam(value = "memberUid") String memberUid,
            @ApiParam(value = "服务订单编号") @RequestParam(value = "orderCode") String orderCode
    ) {
        CmorderDto data = cmordersService.getDtoByOrderCode(storeUid, memberUid, orderCode);
        if (null == data)
            return R.fail("未在门店下发现该服务订单");

        List<Cmpaypics> pays = cmpaypicsService.getByOrderCode(orderCode);
        List<OrderStatusLogs> logs = orderStatusLogsService.listByOrderCode(orderCode);
        List<CmservicesDto> services = cmservicesService.dtoListByOrderCodeAndStatusIn(storeUid, memberUid, orderCode);
        CmorderUtil.setUseLessonCntAndStatusName(services, null);

        if (StringUtils.isNotBlank(data.getReceiptUid())) {
            ReceiptRegisterDto receiptRegister = receiptRegisterService.dtoGetByUid(storeUid, data.getReceiptUid());
            if (receiptRegister != null)
                data.setReceiptRegister(receiptRegister);
        }

        data.setPays(pays);
        data.setServices(services);
        data.setLogs(logs);

        return R.ok(data);
    }


    @ApiOperation(value = "获取订单和服务信息")
    @PostMapping(value = "/getOrderAndServiceList", produces = "application/json; charset=UTF-8")
    public R<Object> getOrderAndServiceList(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "会员uid") @RequestParam(value = "memberUid") String memberUid,
            @ApiParam(value = "服务订单编号") @RequestParam(value = "orderCode") String orderCode
    ) {
        CmorderDto data = cmordersService.getDtoByOrderCode(storeUid, memberUid, orderCode);
        if (null == data)
            return R.fail("未在门店下发现该服务订单");

        List<CmservicesDto> services = cmservicesService.dtoListByOrderCodeAndStatusIn(storeUid, memberUid, orderCode);
        data.setServices(services);

        return R.ok(data);
    }


    @Transactional(rollbackFor = DescribeException.class)
    @ApiOperation(value = "删除服务订单")
    @PostMapping(value = "/dropBean", produces = "application/json; charset=UTF-8")
    public R<Object> dropBean(
            HttpServletRequest request,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "会员uid") @RequestParam(value = "memberUid") String memberUid,
            @ApiParam(value = "服务订单编号") @RequestParam(value = "orderCode") String orderCode
    ) throws Exception {
        R<Object> r = LoginInfoUtil.getLoginDto(request);
        if (R.isError(r)) throw new DescribeException(500, r.getMsg());
        LoginDataDto loginDto = (LoginDataDto) r.getData();

        Cmorders data = cmordersService.getByOrderCode(null, memberUid, orderCode);
        if (data == null)
            return R.fail("订单获取失败");
        if (data.getStatus().equals(1))
            return R.fail("审批已通过，不能操作");
        if (data.getOrderState() != null && !data.getOrderState().equals(EnumType.CmOrderState.OK.getState()))
            return R.fail("状态：" + data.getOrderStateName() + "，不能操作");

        if (AccountUtil.isStoreManager(loginDto.getStoreRoles())) {
            // 店长超过30天，不能删除
            if (TimeUtil.moreThanDay(data.getAddTime(), 30))
                return R.fail("订单提交超过30天，不能操作");
        } else {
            // 非店长超过3天，不能删除
            if (TimeUtil.moreThanDay(data.getAddTime(), 3))
                return R.fail("订单提交超过3天，不能操作");
        }

        // 判断服务项目是否开卡
        boolean b = cmservicesService.haveOpenCard(orderCode);
        if (b)
            return R.fail("发现有已开卡的服务项目，不能删除");

        // 删除订单
        long l = cmordersService.dropBean(storeUid, memberUid, orderCode);
        if (l <= 0)
            return R.fail("服务订单删除失败");

        // 删除服务
        cmservicesService.dropByOrderCode(storeUid, memberUid, orderCode);

        // 删除付款截图
        List<String> urlList = cmpaypicsService.urlListByOrderCode(orderCode);
        if (CollectionUtils.isNotEmpty(urlList)) {
            cmpaypicsService.dropByOrderCode(orderCode);
            LocalFileUtil.deleteImgList(LocalFileUtil.payImgBaseDir, urlList);
        }

        // 清空门店缓存
        redisService.setNullLike(RedisParam.STORE_DATA + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_SERVICE + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_KINDS + storeUid);
        return R.ok();
    }

    @ApiOperation(value = "获取服务项目的信息")
    @PostMapping(value = "/getServiceInfo", produces = "application/json; charset=UTF-8")
    public R<Object> getServiceInfo(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "会员uid") @RequestParam(value = "memberUid") String memberUid,
            @ApiParam(value = "服务订单编号") @RequestParam(value = "orderCode") String orderCode,
            @ApiParam(value = "服务项目uid") @RequestParam(value = "serviceUid") String serviceUid
    ) {
        CmservicesDto data = cmservicesService.dtoByUid(storeUid, memberUid, orderCode, serviceUid);
        return R.ok(data);
    }

    @ApiOperation(value = "编辑订单的服务项目")
    @PostMapping(value = "/editServiceInfo", produces = "application/json; charset=UTF-8")
    public R<Object> editServiceInfo(
            HttpServletRequest request,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "服务订单编号") @RequestParam(value = "orderCode") String orderCode,
            @ApiParam(value = "服务项目uid") @RequestParam(value = "serviceUid") String serviceUid,
            @ApiParam(value = "导读员工uid") @RequestParam(value = "readStaffUid", required = false) String readStaffUid,
            @ApiParam(value = "导读员工姓名") @RequestParam(value = "staffFullName", required = false) String staffFullName,
            @ApiParam(value = "导读员工昵称") @RequestParam(value = "staffNickName", required = false) String staffNickName,
            @ApiParam(value = "导读员工电话") @RequestParam(value = "staffPriPhone", required = false) String staffPriPhone,
            @ApiParam(value = "备注") @RequestParam(value = "remarks", required = false) String remarks
    ) throws Exception {
        Cmservices data = cmservicesService.getByUid(storeUid, orderCode, serviceUid);
        if (null == data)
            return R.fail("服务项目获取失败");
        if (null != data.getChangeStatus() && !data.getChangeStatus().equals(EnumType.ServiceStatus.NO_CHANGE.getStatus()))
            return R.fail("该服务项目是" + data.getChangeStatusName() + "，不能操作");
        if (!data.getStatus().equals(EnumType.ServiceStatus.OPEN_CARD.getStatus()) && !data.getStatus().equals(EnumType.ServiceStatus.PAUSE_CARD.getStatus()))
            return R.fail("服务状态不是开卡或暂停，不能操作");
        if (data.getEnding().equals(1))
            return R.fail("已结课，不能操作");

        Cmorders cmorders = cmordersService.getByOrderCode(null, null, orderCode);
        if (null == cmorders)
            return R.fail("订单信息获取失败");
        if (null == cmorders.getOrderState())
            return R.fail("订单不能操作，状态异常");

        if (StringUtils.isBlank(readStaffUid)) {
            if (StringUtils.isNotBlank(staffFullName) || StringUtils.isNotBlank(staffPriPhone)) {
                if (StringUtils.isBlank(staffFullName))
                    return R.fail("请填写导读员的姓名");
                if (StringUtils.isBlank(staffPriPhone)) {
                    return R.fail("请填写导读员的联系电话");
                } else {
                    if (staffPriPhone.length() != 11)
                        return R.fail("导读员的联系电话格式错误");
                }
            }
        }

        boolean l = cmservicesService.updateInfo(storeUid, orderCode, serviceUid, staffUid, staffName,
                readStaffUid, staffFullName, staffNickName, staffPriPhone, remarks);
        if (!l) return R.fail("更新失败");

        return R.ok();
    }


    @ApiOperation(value = "设置订单服务的开卡状态")
    @PostMapping(value = "/setServiceStatus", produces = "application/json; charset=UTF-8")
    public R<Object> setServiceStatus(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "服务订单编号") @RequestParam(value = "orderCode") String orderCode,
            @ApiParam(value = "服务项目uid") @RequestParam(value = "serviceUid") String serviceUid,
            @ApiParam(value = "开始日期") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "暂停/继续服务日期") @RequestParam(value = "pauseDate", required = false) String pauseDate,
            @ApiParam(value = "状态 未开卡:-1，暂停服务:0，开卡:1，继续服务:2") @RequestParam(value = "status") int status,
            @ApiParam(value = "主科目UID") @RequestParam(value = "mainSubjectUid", required = false) String mainSubjectUid,
            @ApiParam(value = "科目UID") @RequestParam(value = "subjectUid", required = false) String subjectUid,
            @ApiParam(value = "阶段uid") @RequestParam(value = "stageUid", required = false) String stageUid,
            @ApiParam(value = "支付类型 1.微信 2.支付宝 3.激活码") @RequestParam(value = "payType", required = false) Integer payType
    ) throws Exception {
        Cmservices data = cmservicesService.getByUid(storeUid, orderCode, serviceUid);
        if (null == data)
            return R.fail("服务获取失败");
        if (data.getStatus().equals(status))
            return R.fail("不能设置同样的状态");
        if (StringUtils.isBlank(data.getOrderType()))
            return R.fail("请先维护该服务关联订单的收入类型");
        if (null == data.getProjectUid())
            return R.fail("未获取到基础服务标识，不能操作");
        if (null != data.getChangeStatus() && !data.getChangeStatus().equals(EnumType.ServiceStatus.NO_CHANGE.getStatus()))
            return R.fail("服务是" + data.getChangeStatusName() + "，不能操作");
        if (data.getEnding().equals(1))
            return R.fail("已结课，不能操作");

        Cmorders cmorders = cmordersService.getByOrderCode(null, null, orderCode);
        if (null == cmorders)
            return R.fail("订单信息获取失败");

        Members member = membersService.getByUid(storeUid, data.getMemberUid());
        if (null == member)
            return R.fail("会员获取失败");
        if (!member.getEnabled().equals(1))
            return R.fail("会员已被禁用，不能操作");

        StoreProjects storeProjects = storeProjectsService.getByUid(data.getProjectUid());
        if (null == storeProjects)
            return R.fail("基础服务获取失败");
        if (!storeProjects.getEnabled().equals(1))
            return R.fail(storeProjects.getProjectName() + " 已被禁用，不能操作");

        String mainSubjectName = null;
        String subjectName = null;
        String stageName = null;
        Double activateAmount = 0.0d;
        String activationTypeUid = null;
        Integer isPay = storeProjects.getIsPay();
        if (isPay == 1) {
            if (StringUtils.isBlank(mainSubjectUid) || StringUtils.isBlank(subjectUid) || StringUtils.isBlank(stageUid))
                return R.fail("请选择科目、阶段");
            if (!payType.equals(1) && !payType.equals(2) && !payType.equals(3))
                return R.fail("请选择支付类型");

            Subjects mainSubjects = subjectsService.getByUid(mainSubjectUid);
            Subjects subjects = subjectsService.getByUid(subjectUid);
            Subjects stageSubjects = subjectsService.getByUid(stageUid);
            mainSubjectName = mainSubjects.getSubjectName();
            subjectName = subjects.getSubjectName();
            stageName = stageSubjects.getSubjectName();
            if (mainSubjects == null || subjects == null || stageSubjects == null)
                return R.fail("科目获取失败");

            activateAmount = stageSubjects.getActivateAmount();
            if (activateAmount == null || activateAmount <= 0)
                return R.fail("科目激活金额未设置");
            activationTypeUid = stageSubjects.getActivationTypeUid();
            if (StringUtils.isBlank(activationTypeUid))
                return R.fail("科目激活码类型未设置");
            Long codeNum = cmactivationCodeService.getCodeNum(corpUid, storeUid, activationTypeUid);
            if (codeNum == null || codeNum <= 0)
                return R.fail("激活码数量不足");
        }

        String content = "";
        String followType = EnumType.Follow.OPEN_CARD.getType();
        String followTypeName = EnumType.Follow.OPEN_CARD.getName();

        if (data.getStatus().equals(1) && status == 0) {
            // 暂停服务
            if (StringUtils.isBlank(pauseDate))
                return R.fail("请设置暂停服务时间");
            Date pauseDateValue = DateUtil.parseDate(pauseDate);

            boolean l = cmservicesService.setStatusV3(storeUid, orderCode, serviceUid, staffUid, staffName,
                    null, null, pauseDateValue,
                    EnumType.ServiceStatus.PAUSE_CARD.getStatus(), EnumType.ServiceStatus.PAUSE_CARD.getName());
            if (!l)
                return R.fail("暂停服务失败");

            // 服务操作记录
            ServiceStatusLogs statusLog = CmorderUtil.newStatusLog(data, staffUid, staffName, status, pauseDateValue, null, null);
            serviceStatusLogsService.saveOrUpdate(statusLog);
            // 跟进内容
            content = " 服务已暂停，暂停时间：" + DateUtil.getDefaultTime2DateStr(pauseDateValue);
            followType = EnumType.Follow.PAUSE_CARD.getType();
            followTypeName = EnumType.Follow.PAUSE_CARD.getName();
        } else if (data.getStatus().equals(-1) && status == 1) {
            // 开卡
            if (StringUtils.isBlank(beginDate))
                return R.fail("请设置开始时间");
            Date beginDateValue = DateUtil.parseDate(beginDate);
            // 计算结束日期
            Date endDateValue = DateUtil.addDays(beginDateValue, data.getServiceDays());

            LocalDateTime usedTime = LocalDateTime.now();
            if (isPay == 1) {
                Boolean activate = cmactivationCodeService.getCodeForActivate(
                        corpUid, storeUid, activationTypeUid,
                        cmorders.getOrderCode(), serviceUid, member.getUid(), member.getMemberName(), usedTime, staffUid, staffName
                );
                if (!activate)
                    return R.fail("激活码不足或使用失败！");
            }

            boolean l = cmservicesService.setStatusAndActivate(
                    storeUid, orderCode, serviceUid, staffUid, staffName, beginDateValue, endDateValue,
                    EnumType.ServiceStatus.OPEN_CARD.getStatus(), EnumType.ServiceStatus.OPEN_CARD.getName(),
                    mainSubjectUid, mainSubjectName, subjectUid, subjectName, stageUid, stageName, payType, activateAmount
            );
            if (!l)
                return R.fail("开卡失败");

            // 服务操作记录
            ServiceStatusLogs statusLog = CmorderUtil.newStatusLog(data, staffUid, staffName, status, null, beginDateValue, endDateValue);
            serviceStatusLogsService.saveOrUpdate(statusLog);

            // 跟进内容
            content = " 服务已开卡，服务周期：" + beginDate + "至" + DateUtil.getDefaultTime2DateStr(endDateValue);
        } else if (data.getStatus().equals(0) && status == 2) {
            // 继续服务
            if (StringUtils.isBlank(pauseDate))
                return R.fail("请设置继续服务时间");
            if (null == data.getEndDate())
                return R.fail("结束时间不能为空");
            Date pauseDateValue = DateUtil.parseDate(pauseDate);
            // 重新计算结束日期，原结束日期+天数（继续日期-暂停日期）
            int day = DateUtil.getQuot(data.getPauseDate(), pauseDateValue);
            Date endDateValue = DateUtil.addDays(data.getEndDate(), day);

            boolean l = cmservicesService.setStatusV3(storeUid, orderCode, serviceUid, staffUid, staffName,
                    null, endDateValue, pauseDateValue,
                    EnumType.ServiceStatus.OPEN_CARD.getStatus(), EnumType.ServiceStatus.OPEN_CARD.getName());
            if (!l)
                return R.fail("继续服务失败");

            // 服务操作记录
            ServiceStatusLogs statusLog = CmorderUtil.newStatusLog(data, staffUid, staffName, status, pauseDateValue, data.getBeginDate(), endDateValue);
            serviceStatusLogsService.saveOrUpdate(statusLog);

            // 跟进内容
            content = " 已继续服务，继续日期：" + DateUtil.getDefaultTime2DateStr(pauseDateValue)
                    + "，服务周期：" + DateUtil.getDefaultTime2DateStr(data.getBeginDate()) + "至" + DateUtil.getDefaultTime2DateStr(endDateValue);
            followType = EnumType.Follow.CONTINUE_CARD.getType();
            followTypeName = EnumType.Follow.CONTINUE_CARD.getName();
        } else {
            return R.fail("状态错误，不能操作");
        }

        Date followTime = DateUtil.getNowDatetime();
        // 创建订单详情的操作记录
        content = data.getProductName() + content;
        MemberFollow follow = FollowUtil.newFollow(data.getCorpUid(), storeUid, storeName, staffUid, staffName, member.getUid(),
                member.getMemberName(), followType, followTypeName, content, serviceUid, followTime);
        memberFollowService.saveOrUpdate(follow);
        // 更新会员的最后跟进信息
        membersService.updateLastFollowInfo(storeUid, data.getMemberUid(), follow.getUid(), followTime);

        return R.ok();
    }


    @ApiOperation(value = "根据会员订单号获取服务")
    @PostMapping(value = "/getOrderServices", produces = "application/json; charset=UTF-8")
    public R<Object> getOrderServices(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "服务订单编号") @RequestParam(value = "orderCode") String orderCode
    ) {
        List<CmservicesDto> list = cmservicesService.dtoListByOrderCodeOrRelationCode(storeUid, orderCode);

        if (CollectionUtils.isNotEmpty(list)) {
            // 已开卡且可排活动的服务uid集合，获取消耗数量
            Map<String, Long> consumeMap = CmorderUtil.getConsumeLessonMapByDto(list);
            // 服务获取以活动次数，状态名称修改
            CmorderUtil.setUseLessonCntAndStatusName(list, consumeMap);
        }
        return R.ok(list);
    }


    @ApiOperation(value = "审批拒绝-再次提交")
    @PostMapping(value = "/againSubmit", produces = "application/json; charset=UTF-8")
    public R<Object> againSubmit(
            HttpServletRequest request,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "服务订单编号") @RequestParam(value = "orderCode") String orderCode
    ) {
        R<Object> r = LoginInfoUtil.getLoginDto(request);
        if (R.isError(r)) return r;
        LoginDataDto loginDto = (LoginDataDto) r.getData();

        if (!AccountUtil.isStoreManager(loginDto.getStoreRoles()))
            return R.fail("非店长账号，不能操作");

        Cmorders data = cmordersService.getByOrderCode(null, null, orderCode);
        if (data == null)
            return R.fail("会员订单获取失败");
        if (!AccountUtil.isSelfStore(loginDto.getCurrentOperationType()))
            return R.fail("非自营门店的会员订单，不能操作");
        if (!data.getStatus().equals(-1))
            return R.fail("审批状态不是已退回，不能操作");

        boolean l = cmordersService.updateStatus(orderCode, 0, "待审批");
        if (!l)
            return R.fail("操作失败");

        return R.ok();
    }


    @ApiOperation(value = "判断订单能否变更或退费")
    @PostMapping(value = "/judgeChangeOrRefund", produces = "application/json; charset=UTF-8")
    public R<Object> judgeChangeOrRefund(
            HttpServletRequest request,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "会员uid") @RequestParam(value = "memberUid") String memberUid,
            @ApiParam(value = "变更/退费的订单号") @RequestParam(value = "orderCode") String orderCode,
            @ApiParam(value = "变更/退费的服务uid集合") @RequestParam(value = "serviceUids", required = false) List<String> serviceUids,
            @ApiParam(value = "变更日期 yyyy-MM-dd") @RequestParam(value = "changeDate", required = false) String changeDate,
            @ApiParam(value = "变更类型 1.变更 2.退费") @RequestParam(value = "type") Integer type
    ) throws Exception {
        R<Object> r = LoginInfoUtil.getLoginDto(request);
        if (R.isError(r)) return r;
        LoginDataDto loginDto = (LoginDataDto) r.getData();

        if (!AccountUtil.isStoreManager(loginDto.getStoreRoles()))
            return R.fail("非店长账号，不能操作");
        if (!type.equals(1) && !type.equals(2))
            return R.fail("变更类型错误");
        if (null == changeDate)
            return R.fail("请选择变更日期");

        Members members = membersService.getByUid(storeUid, memberUid);
        if (null == members)
            return R.fail("会员信息获取失败");

        Cmorders cmorders = cmordersService.getByOrderCode(storeUid, memberUid, orderCode);
        if (null == cmorders)
            return R.fail("订单信息获取失败");
        if (null == cmorders.getStatus())
            return R.fail("订单的状态未知，不能操作");
        if (!cmorders.getStatus().equals(1))
            return R.fail("还未审批通过，不能操作");
        // 订单状态 1.正常 2.变更 3.退费 4.已变更 5.已退费 6.已变更/退费
        Integer orderState = cmorders.getOrderState();
        if (null == orderState || (!orderState.equals(EnumType.CmOrderState.OK.getState()) && !orderState.equals(EnumType.CmOrderState.CHANGE.getState())))
            return R.fail("订单不能操作，状态：" + cmorders.getOrderStateName());

        // 是否订金订单
        boolean isEmd = cmorders.getOrderType().equals(EnumType.OrderType.EMD.getType());
        // 原订单的结转金额
        double carriedForwardAmount = 0d;
        List<Cmservices> checkServiceList = new ArrayList<>();
        if (isEmd) {
            if (type.equals(1))
                return R.fail("订单的收入类型是订金，不能申请变更");
            List<Cmservices> servicesList = cmservicesService.listByOrderCodeAndChangStatusIsNull(storeUid, memberUid, orderCode);
            if (CollectionUtils.isNotEmpty(servicesList))
                return R.fail("订单的收入类型是订金且有服务记录，不能操作");
        } else {
            if (CollectionUtils.isEmpty(serviceUids))
                return R.fail("请先选择服务");
            List<Cmservices> servicesList = cmservicesService.listByOrderCodeAndChangStatusIsNull(storeUid, memberUid, orderCode);
            if (CollectionUtils.isEmpty(servicesList))
                return R.fail("订单的服务获取失败");
            // 选中的服务
            checkServiceList = new ArrayList<>();
            for (Cmservices dto : servicesList) {
                if (serviceUids.contains(dto.getUid()))
                    checkServiceList.add(dto);
            }
            if (CollectionUtils.isEmpty(checkServiceList))
                return R.fail("未查询到选中的服务");

            // 变更日期
            Date changeDateValue = DateUtil.parseDate(changeDate);
            // 判断服务集合能否变更
            if (type.equals(1)) {
                String resultMsg = CmorderUtil.judgeChangeServicesV2(checkServiceList, changeDateValue);
                if (StringUtils.isNotBlank(resultMsg))
                    return R.fail(resultMsg);
            } else {
                String resultMsg = CmorderUtil.judgeRefundServicesV2(checkServiceList, changeDateValue, null);
                if (StringUtils.isNotBlank(resultMsg))
                    return R.fail(resultMsg);
            }
            carriedForwardAmount = CmorderUtil.getCarriedForwardAmountV2(servicesList, changeDateValue);
        }

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("servicesList", checkServiceList);
        jsonObject.put("carriedForwardAmount", carriedForwardAmount);

        return R.ok(jsonObject);
    }

    @Transactional(rollbackFor = DescribeException.class)
    @ApiOperation(value = "设置订单服务变更")
    @PostMapping(value = "/setOrderChange", produces = "application/json; charset=UTF-8")
    public R<Object> setOrderChange(
            HttpServletRequest request,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "会员uid") @RequestParam(value = "memberUid") String memberUid,
            @ApiParam(value = "变更的订单编号") @RequestParam(value = "orderCode") String orderCode,
            @ApiParam(value = "变更服务uid集合") @RequestParam(value = "serviceUids") String serviceUids,
            @ApiParam(value = "变更日期 yyyy-MM-dd") @RequestParam(value = "changeDate") String changeDate,
            @ApiParam(value = "收入类型 体验会员:EXP，正式会员新签:NEW，续费:RENEW，拓科:EXT，订金:EMD")
            @RequestParam(value = "orderType") String orderType,
            @ApiParam(value = "服务json [{uid:'',isGift:0,productCode:'',productName:'',serviceCycle:0,cycleName:'',serviceDays:0,totalLessons:0}]")
            @RequestParam(value = "serviceJson") String serviceJson,
            @ApiParam(value = "合同编号") @RequestParam(value = "contractCode", required = false) String contractCode,
            @ApiParam(value = "收款金额") @RequestParam(value = "orderAmount", required = false) Double orderAmount,
            @ApiParam(value = "收款日期 yyyy-MM-dd") @RequestParam(value = "orderDate", required = false) String orderDate,
            @ApiParam(value = "礼品领取 已领取:1，未领取:0") @RequestParam(value = "giftGotten", required = false) String giftGotten,
            @ApiParam(value = "礼品备注") @RequestParam(value = "giftRemark", required = false) String giftRemark,
            @ApiParam(value = "签单人uid") @RequestParam(value = "saleStaffUid") String saleStaffUid,
            @ApiParam(value = "签单人姓名") @RequestParam(value = "saleStaffFullName") String saleStaffFullName,
            @ApiParam(value = "备注") @RequestParam(value = "orderRemark", required = false) String orderRemark,
            @ApiParam(value = "收款方式 收款码:CCB_QR，开单工具:SALE_TOOL，现金:CASH，银行转账:BANK，收银机/POS机 :POS")
            @RequestParam(value = "payChannelCode", required = false) String payChannelCode,
            @ApiParam(value = "结转金额") @RequestParam(value = "carriedForwardAmount") Double carriedForwardAmount,
            @ApiParam(value = "付款截图json [{id:0,imgUrl:''}]") @RequestParam(value = "imgJson", required = false) String imgJson
    ) throws Exception {
        R<Object> r = LoginInfoUtil.getLoginDto(request);
        if (R.isError(r)) return r;
        LoginDataDto loginDto = (LoginDataDto) r.getData();

        if (!AccountUtil.isStoreManager(loginDto.getStoreRoles()))
            return R.fail("非店长账号，不能操作");
        if (StringUtils.isBlank(orderType))
            return R.fail("请选择收入类型");
        if (orderType.equals(EnumType.OrderType.EMD.getType()))
            return R.fail("申请变更时，收入类型不能选订金");
        if (StringUtils.isBlank(serviceUids))
            return R.fail("请先选择要变更的服务");
        List<String> uids = JSONArray.parseArray(serviceUids, String.class);
        if (CollectionUtils.isEmpty(uids))
            return R.fail("请先选择要变更的服务");
        if (null == orderAmount || orderAmount < 0)
            return R.fail("请填写正确的收款金额");
        if (null == carriedForwardAmount || carriedForwardAmount < 0)
            return R.fail("结转金额错误");
        if (StringUtils.isBlank(changeDate))
            return R.fail("请选择变更日期");
        if (StringUtils.isBlank(orderDate))
            return R.fail("请选择收款日期");
        if (StringUtils.isBlank(saleStaffUid) || StringUtils.isBlank(saleStaffFullName))
            return R.fail("请选择签单人或完善签单人的信息");
        if (StringUtils.isBlank(orderRemark))
            return R.fail("请填写备注");
        if (StringUtils.isBlank(serviceJson))
            return R.fail("请添加新服务");
        List<Cmservices> newServicesList = JSONObject.parseArray(serviceJson, Cmservices.class);
        if (CollectionUtils.isEmpty(newServicesList))
            return R.fail("服务转换失败");
        List<Cmpaypics> pics = new ArrayList<>();
        if (StringUtils.isNotBlank(imgJson)) {
            if (StringUtils.isBlank(payChannelCode))
                return R.fail("请选择收款方式");
            pics = JSONObject.parseArray(imgJson, Cmpaypics.class);
            if (CollectionUtils.isEmpty(pics))
                return R.fail("付款截图转换失败");
        } else {
            if (orderAmount > 0)
                return R.fail("收款金额大于0，需上传付款截图");
        }

        Cmorders cmorders = cmordersService.getByOrderCode(storeUid, memberUid, orderCode);
        if (null == cmorders)
            return R.fail("变更的订单获取失败");
        if (null == cmorders.getStatus())
            return R.fail("订单的状态未知，不能操作");
        if (!cmorders.getStatus().equals(1))
            return R.fail("还未审批通过，不能操作");
        // 订单状态 1.正常 2.变更 3.退费 4.已变更 5.已退费 6.已变更/退费
        Integer orderState = cmorders.getOrderState();
        if (null == orderState || (!orderState.equals(EnumType.CmOrderState.OK.getState()) && !orderState.equals(EnumType.CmOrderState.CHANGE.getState())))
            return R.fail("订单不能操作，状态：" + cmorders.getOrderStateName());
        // 是否订金订单
        boolean isEmd = cmorders.getOrderType().equals(EnumType.OrderType.EMD.getType());
        if (isEmd)
            return R.fail("订单的收入类型是订金，不能申请变更");

        // 验证签单人
        Staff saleStaff = staffService.getByUid(saleStaffUid);
        String msg = judgeSaleStaff(saleStaff);
        if (StringUtils.isNotBlank(msg))
            return R.fail(msg);

        Members members = membersService.getByUid(storeUid, memberUid);
        if (null == members)
            return R.fail("会员获取失败");
        String membersCorpUid = members.getCorpUid();

        //TODO 判断服务集合的变更条件
        List<Cmservices> servicesList = cmservicesService.listByOrderCodeAndChangStatusIsNullAndEnding(storeUid, memberUid, orderCode);
        if (CollectionUtils.isEmpty(servicesList))
            return R.fail("订单的服务获取失败");

        List<String> projectUids = newServicesList.stream().map(Cmservices::getProjectUid)
                .filter(StringUtils::isNotBlank)
                .distinct().collect(Collectors.toList());
        // 选中的服务
        List<Cmservices> checkServiceList = new ArrayList<>();
        List<Cmservices> unCheckServiceList = new ArrayList<>();
        for (Cmservices service : servicesList) {
            if (serviceUids.contains(service.getUid())) {
                checkServiceList.add(service);
            } else {
                unCheckServiceList.add(service);
                projectUids.add(service.getProjectUid());
            }
        }
        // 变更日期
        Date changeDateValue = DateUtil.parseDate(changeDate);
        // 检查服务能否变更
        String resultMsg = CmorderUtil.judgeChangeServicesV2(checkServiceList, changeDateValue);
        if (StringUtils.isNotBlank(resultMsg))
            return R.fail(resultMsg);

        List<StoreProjects> projectsList = storeProjectsService.listByUids(projectUids);
        if (CollectionUtils.isEmpty(projectsList))
            return R.fail("服务信息获取失败");

        //TODO 创建变更的服务
        // 收款日期
        Date orderDateValue = DateUtil.parseDate(orderDate);
        String newChangeOrderCode = KitUtil.getMemberServiceCode();
        List<Cmservices> newConsumeAndChangeServiceList = new ArrayList<>();
        List<ServiceStatusLogs> newStatusLogs = new ArrayList<>();
        List<String> invalidServiceUidList = new ArrayList<>();
        List<String> changeServiceUidList = new ArrayList<>();
        // 设置服务变更
        for (Cmservices cmservices : servicesList) {
            int logStatus = 0;
            if (cmservices.getStatus().equals(pauseCardStatus) || cmservices.getStatus().equals(openCardStatus)) {
                // 如果已开卡，创建消耗服务记录和变更服务记录
                List<Cmservices> newServices = CmorderUtil.newConsumeAndChangeServiceListV2(
                        cmservices, staffUid, staffName, storeName, members.getMemberName(), newChangeOrderCode,
                        cmorders.getOrderType(), changeDateValue
                );
                newConsumeAndChangeServiceList.addAll(newServices);
                invalidServiceUidList.add(cmservices.getUid());
                logStatus = invalidStatus;
            } else if (cmservices.getStatus().equals(noCardStatus)) {
                // 如果服务还未开卡，直接设置已变更
                changeServiceUidList.add(cmservices.getUid());
                logStatus = changeStatus;
            }
            // 创建服务操作记录
            ServiceStatusLogs statusLog = CmorderUtil.newStatusLog(cmservices, staffUid, staffName, logStatus, null, null, null);
            newStatusLogs.add(statusLog);
        }

        // 原服务设置已变更
        if (CollectionUtils.isNotEmpty(invalidServiceUidList)) {
            boolean b = cmservicesService.updateChangeStatusByUidList(invalidServiceUidList, memberUid, orderCode, staffUid, staffName, newChangeOrderCode, changeDateValue, invalidStatus, invalidName);
            if (!b) throw new DescribeException("服务设置已变更失败");
        }
        // 原服务设置已变更
        if (CollectionUtils.isNotEmpty(changeServiceUidList)) {
            boolean b = cmservicesService.updateChangeStatusByUidList(changeServiceUidList, memberUid, orderCode, staffUid, staffName, newChangeOrderCode, changeDateValue, changeStatus, changeName);
            if (!b) throw new DescribeException("服务设置已变更失败");
        }
        // 保存消耗和变更的服务记录
        if (CollectionUtils.isNotEmpty(newConsumeAndChangeServiceList))
            cmservicesService.saveOrUpdateBatch(newConsumeAndChangeServiceList);
        // 保存服务操作记录
        serviceStatusLogsService.saveBatch(newStatusLogs);

        //TODO 创建新的订单和新服务
        Map<String, StoreProjects> projectMap = projectsList.stream().collect(Collectors.toMap(StoreProjects::getUid, Function.identity()));
        // 保存新添加的服务
        List<Cmservices> newServiceList = new ArrayList<>();
        for (Cmservices service : newServicesList) {
            StoreProjects storeProject = projectMap.get(service.getProjectUid());
            Cmservices newData = CmorderUtil.newChangeService(service, storeProject, newChangeOrderCode, orderType,
                    membersCorpUid, storeUid, storeName, memberUid, members.getMemberName(), staffUid, staffName);
            newServiceList.add(newData);
        }
        // 未选中的服务复制到新订单
        if (CollectionUtils.isNotEmpty(unCheckServiceList)) {
            for (Cmservices service : unCheckServiceList) {
                Cmservices newData = CmorderUtil.copyService(
                        service, changeDateValue,
                        newChangeOrderCode, orderType, membersCorpUid, storeUid, storeName, memberUid, members.getMemberName(), staffUid, staffName
                );
                if (newData != null)
                    newServiceList.add(newData);
            }
        }
        cmservicesService.saveOrUpdateBatch(newServiceList);

        // 付款图片
        if (CollectionUtils.isNotEmpty(pics)) {
            List<Cmpaypics> newList = new ArrayList<>();
            for (Cmpaypics pic : pics) {
                pic.setOrderCode(newChangeOrderCode);
                pic.setStaffUid(staffUid);
                newList.add(pic);
            }
            cmpaypicsService.saveOrUpdateBatch(newList);
        }

        //  创建变更订单
        Cmorders newChangeOrder = CmorderUtil.newChangeCmorder(
                membersCorpUid, storeUid, storeName, staffUid, staffName, newChangeOrderCode, memberUid, members.getMemberName(),
                saleStaffUid, saleStaffFullName, saleStaff.getPriPhone(), saleStaff.getPubPhone(), saleStaff.getNickName(),
                contractCode, orderAmount, orderDateValue, giftGotten, giftRemark, orderRemark, payChannelCode, orderType,
                orderCode, carriedForwardAmount, newServiceList.size() + newConsumeAndChangeServiceList.size()
        );
        cmordersService.saveOrUpdate(newChangeOrder);

        // 更新原订单的状态
        boolean l = cmordersService.updateOrderStateAndChangeDate(orderCode, staffUid, staffName,
                EnumType.CmOrderState.AL_CHANGE.getState(), EnumType.CmOrderState.AL_CHANGE.getName(), changeDateValue);
        if (!l)
            throw new DescribeException("更新订单变更信息失败");

        // 保存申请记录
        String applyCode = saveApplyLog(
                1, "变更", membersCorpUid, storeUid, staffUid, staffName, memberUid,
                orderCode, NepUtil.nullToZero(cmorders.getOrderAmount()), NepUtil.nullToZero(cmorders.getCarriedForwardAmount()),
                orderAmount, carriedForwardAmount, changeDateValue, orderRemark, newChangeOrderCode, null, pics
        );

        // 创建跟进记录
        saveFollowLog(
                1, membersCorpUid, storeUid, storeName, staffUid, staffName, memberUid, members.getMemberName(), orderCode,
                newChangeOrderCode, null, applyCode
        );

        // 订单金额拆分
        msg = orderAmountSplitUtil.splitServiceAmount(newChangeOrder, carriedForwardAmount, null);
        if (StringUtils.isNotBlank(msg))
            throw new DescribeException(msg);

        // 清空门店缓存
        redisService.setNullLike(RedisParam.STORE_DATA + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_SERVICE + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_KINDS + storeUid);

        return R.ok();
    }

    @Transactional(rollbackFor = DescribeException.class)
    @ApiOperation(value = "设置订单服务变更")
    @PostMapping(value = "/v2/setOrderChange", produces = "application/json; charset=UTF-8")
    public R<Object> setOrderChangeV2(
            HttpServletRequest request,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "会员uid") @RequestParam(value = "memberUid") String memberUid,
            @ApiParam(value = "变更的订单编号") @RequestParam(value = "orderCode") String orderCode,
            @ApiParam(value = "变更服务uid集合") @RequestParam(value = "serviceUids") String serviceUids,
            @ApiParam(value = "变更日期 yyyy-MM-dd") @RequestParam(value = "changeDate") String changeDate,
            @ApiParam(value = "收入类型 体验会员:EXP，正式会员新签:NEW，续费:RENEW，拓科:EXT，订金:EMD")
            @RequestParam(value = "orderType") String orderType,
            @ApiParam(value = "服务json [{uid:'',isGift:0,productCode:'',productName:'',serviceCycle:0,cycleName:'',serviceDays:0,totalLessons:0}]")
            @RequestParam(value = "serviceJson") String serviceJson,
            @ApiParam(value = "合同编号") @RequestParam(value = "contractCode", required = false) String contractCode,
            @ApiParam(value = "收款金额") @RequestParam(value = "orderAmount", required = false) Double orderAmount,
            @ApiParam(value = "收款日期 yyyy-MM-dd") @RequestParam(value = "orderDate", required = false) String orderDate,
            @ApiParam(value = "礼品领取 已领取:1，未领取:0") @RequestParam(value = "giftGotten", required = false) String giftGotten,
            @ApiParam(value = "礼品备注") @RequestParam(value = "giftRemark", required = false) String giftRemark,
            @ApiParam(value = "签单人uid") @RequestParam(value = "saleStaffUid") String saleStaffUid,
            @ApiParam(value = "签单人姓名") @RequestParam(value = "saleStaffFullName") String saleStaffFullName,
            @ApiParam(value = "备注") @RequestParam(value = "orderRemark", required = false) String orderRemark,
            @ApiParam(value = "收款方式 收款码:CCB_QR，开单工具:SALE_TOOL，现金:CASH，银行转账:BANK，收银机/POS机 :POS")
            @RequestParam(value = "payChannelCode", required = false) String payChannelCode,
            @ApiParam(value = "结转金额") @RequestParam(value = "carriedForwardAmount") Double carriedForwardAmount,
            @ApiParam(value = "付款截图json [{id:0,imgUrl:''}]") @RequestParam(value = "imgJson", required = false) String imgJson
    ) throws Exception {
        R<Object> r = LoginInfoUtil.getLoginDto(request);
        if (R.isError(r)) return r;
        LoginDataDto loginDto = (LoginDataDto) r.getData();

        if (!AccountUtil.isStoreManager(loginDto.getStoreRoles()))
            return R.fail("非店长账号，不能操作");
        if (StringUtils.isBlank(orderType))
            return R.fail("请选择收入类型");
        if (orderType.equals(EnumType.OrderType.EMD.getType()))
            return R.fail("申请变更时，收入类型不能选订金");
        if (StringUtils.isBlank(serviceUids))
            return R.fail("请先选择要变更的服务");
        List<String> uids = JSONArray.parseArray(serviceUids, String.class);
        if (CollectionUtils.isEmpty(uids))
            return R.fail("请先选择要变更的服务");
        if (null == orderAmount || orderAmount < 0)
            return R.fail("请填写正确的收款金额");
        if (null == carriedForwardAmount || carriedForwardAmount < 0)
            return R.fail("结转金额错误");
        if (StringUtils.isBlank(changeDate))
            return R.fail("请选择变更日期");
        if (StringUtils.isBlank(orderDate))
            return R.fail("请选择收款日期");
        if (StringUtils.isBlank(saleStaffUid) || StringUtils.isBlank(saleStaffFullName))
            return R.fail("请选择签单人或完善签单人的信息");
        if (StringUtils.isBlank(orderRemark))
            return R.fail("请填写备注");
        if (StringUtils.isBlank(serviceJson))
            return R.fail("请添加新服务");
        List<Cmservices> newServicesList = JSONObject.parseArray(serviceJson, Cmservices.class);
        if (CollectionUtils.isEmpty(newServicesList))
            return R.fail("服务转换失败");
        List<Cmpaypics> pics = new ArrayList<>();
        if (StringUtils.isNotBlank(imgJson)) {
            if (StringUtils.isBlank(payChannelCode))
                return R.fail("请选择收款方式");
            pics = JSONObject.parseArray(imgJson, Cmpaypics.class);
            if (CollectionUtils.isEmpty(pics))
                return R.fail("付款截图转换失败");
        } else {
            if (orderAmount > 0)
                return R.fail("收款金额大于0，需上传付款截图");
        }

        Cmorders cmorders = cmordersService.getByOrderCode(storeUid, memberUid, orderCode);
        if (null == cmorders)
            return R.fail("变更的订单获取失败");
        if (null == cmorders.getStatus())
            return R.fail("订单的状态未知，不能操作");
        if (!cmorders.getStatus().equals(1))
            return R.fail("还未审批通过，不能操作");
        // 订单状态 1.正常 2.变更 3.退费 4.已变更 5.已退费 6.已变更/退费
        Integer orderState = cmorders.getOrderState();
        if (null == orderState || (!orderState.equals(EnumType.CmOrderState.OK.getState()) && !orderState.equals(EnumType.CmOrderState.CHANGE.getState())))
            return R.fail("订单不能操作，状态：" + cmorders.getOrderStateName());
        // 是否订金订单
        boolean isEmd = cmorders.getOrderType().equals(EnumType.OrderType.EMD.getType());
        if (isEmd)
            return R.fail("订单的收入类型是订金，不能申请变更");

        // 验证签单人
        Staff saleStaff = staffService.getByUid(saleStaffUid);
        String msg = judgeSaleStaff(saleStaff);
        if (StringUtils.isNotBlank(msg))
            return R.fail(msg);

        Members members = membersService.getByUid(storeUid, memberUid);
        if (null == members)
            return R.fail("会员获取失败");
        String membersCorpUid = members.getCorpUid();

        //TODO 判断服务集合的变更条件
        List<Cmservices> servicesList = cmservicesService.listByOrderCodeAndChangStatusIsNullAndEnding(storeUid, memberUid, orderCode);
        if (CollectionUtils.isEmpty(servicesList))
            return R.fail("订单的服务获取失败");

        List<String> projectUids = newServicesList.stream().map(Cmservices::getProjectUid)
                .filter(StringUtils::isNotBlank)
                .distinct().collect(Collectors.toList());
        // 选中的服务
        List<Cmservices> checkServiceList = new ArrayList<>();
        List<Cmservices> unCheckServiceList = new ArrayList<>();
        for (Cmservices service : servicesList) {
            if (serviceUids.contains(service.getUid())) {
                checkServiceList.add(service);
            } else {
                unCheckServiceList.add(service);
                projectUids.add(service.getProjectUid());
            }
        }
        // 变更日期
        Date changeDateValue = DateUtil.parseDate(changeDate);
        // 检查服务能否变更
        String resultMsg = CmorderUtil.judgeChangeServicesV2(checkServiceList, changeDateValue);
        if (StringUtils.isNotBlank(resultMsg))
            return R.fail(resultMsg);

        List<StoreProjects> projectsList = storeProjectsService.listByUids(projectUids);
        if (CollectionUtils.isEmpty(projectsList))
            return R.fail("服务信息获取失败");

        //TODO 创建变更的服务
        // 收款日期
        Date orderDateValue = DateUtil.parseDate(orderDate);
        String newChangeOrderCode = KitUtil.getMemberServiceCode();
        List<Cmservices> newChangeServiceList = new ArrayList<>();
        List<ServiceStatusLogs> newStatusLogList = new ArrayList<>();
        List<String> changeServiceUidList = new ArrayList<>();
        // 设置服务变更
        for (Cmservices cmservices : checkServiceList) {
            if (cmservices.getStatus().equals(pauseCardStatus) || cmservices.getStatus().equals(openCardStatus) || cmservices.getStatus().equals(noCardStatus)) {
                // 如果已开卡，状态设置已变更并创建变更服务记录
                List<Cmservices> newServices = CmorderUtil.newChangeServiceListV3(
                        cmservices, staffUid, staffName, storeName, members.getMemberName(), newChangeOrderCode, cmorders.getOrderType(), changeDateValue
                );
                newChangeServiceList.addAll(newServices);
                changeServiceUidList.add(cmservices.getUid());
                // 创建服务操作记录
                ServiceStatusLogs statusLog = CmorderUtil.newStatusLog(cmservices, staffUid, staffName, changeStatus, null, null, null);
                newStatusLogList.add(statusLog);
            }
        }
        for (Cmservices cmservices : unCheckServiceList) {
            changeServiceUidList.add(cmservices.getUid());
            // 创建服务操作记录
            ServiceStatusLogs statusLog = CmorderUtil.newStatusLog(cmservices, staffUid, staffName, changeStatus, null, null, null);
            newStatusLogList.add(statusLog);
        }

        // 原服务设置已变更
        if (CollectionUtils.isNotEmpty(changeServiceUidList)) {
            boolean b = cmservicesService.updateChangeStatusByUidList(changeServiceUidList, memberUid, orderCode, staffUid, staffName, newChangeOrderCode, changeDateValue, changeStatus, changeName);
            if (!b) throw new DescribeException("服务设置已变更失败");
        }
        // 保存消耗和变更的服务记录
        if (CollectionUtils.isNotEmpty(newChangeServiceList))
            cmservicesService.saveOrUpdateBatch(newChangeServiceList);
        // 保存服务操作记录
        serviceStatusLogsService.saveBatch(newStatusLogList);

        //TODO 创建新的订单和新服务
        Map<String, StoreProjects> projectMap = projectsList.stream().collect(Collectors.toMap(StoreProjects::getUid, Function.identity()));
        // 保存新添加的服务
        List<Cmservices> newServiceList = new ArrayList<>();
        for (Cmservices service : newServicesList) {
            StoreProjects storeProject = projectMap.get(service.getProjectUid());
            Cmservices newData = CmorderUtil.newChangeService(
                    service, storeProject, newChangeOrderCode, orderType, membersCorpUid, storeUid, storeName, memberUid,
                    members.getMemberName(), staffUid, staffName
            );
            newServiceList.add(newData);
        }
        // 未选中的服务复制到新订单
        if (CollectionUtils.isNotEmpty(unCheckServiceList)) {
            for (Cmservices service : unCheckServiceList) {
                Cmservices newData = CmorderUtil.copyService(
                        service, changeDateValue, newChangeOrderCode, orderType, membersCorpUid, storeUid, storeName,
                        memberUid, members.getMemberName(), staffUid, staffName
                );
                if (newData != null)
                    newServiceList.add(newData);
            }
        }
        cmservicesService.saveOrUpdateBatch(newServiceList);

        // 付款图片
        if (CollectionUtils.isNotEmpty(pics)) {
            List<Cmpaypics> newList = new ArrayList<>();
            for (Cmpaypics pic : pics) {
                pic.setOrderCode(newChangeOrderCode);
                pic.setStaffUid(staffUid);
                newList.add(pic);
            }
            cmpaypicsService.saveOrUpdateBatch(newList);
        }

        //  创建变更订单
        Cmorders newChangeOrder = CmorderUtil.newChangeCmorder(
                membersCorpUid, storeUid, storeName, staffUid, staffName, newChangeOrderCode, memberUid, members.getMemberName(),
                saleStaffUid, saleStaffFullName, saleStaff.getPriPhone(), saleStaff.getPubPhone(), saleStaff.getNickName(),
                contractCode, orderAmount, orderDateValue, giftGotten, giftRemark, orderRemark, payChannelCode, orderType,
                orderCode, carriedForwardAmount, newServiceList.size() + newChangeServiceList.size()
        );
        cmordersService.saveOrUpdate(newChangeOrder);

        // 更新原订单的状态
        boolean l = cmordersService.updateOrderStateAndChangeDate(orderCode, staffUid, staffName,
                EnumType.CmOrderState.AL_CHANGE.getState(), EnumType.CmOrderState.AL_CHANGE.getName(), changeDateValue);
        if (!l)
            throw new DescribeException("更新订单变更信息失败");

        // 保存申请记录
        String applyCode = saveApplyLog(
                1, "变更", membersCorpUid, storeUid, staffUid, staffName, memberUid,
                orderCode, NepUtil.nullToZero(cmorders.getOrderAmount()), NepUtil.nullToZero(cmorders.getCarriedForwardAmount()),
                orderAmount, carriedForwardAmount, changeDateValue, orderRemark, newChangeOrderCode, null, pics
        );

        // 创建跟进记录
        saveFollowLog(
                1, membersCorpUid, storeUid, storeName, staffUid, staffName, memberUid, members.getMemberName(), orderCode,
                newChangeOrderCode, null, applyCode
        );

        // 订单金额拆分
        msg = orderAmountSplitUtil.splitServiceAmount(newChangeOrder, carriedForwardAmount, null);
        if (StringUtils.isNotBlank(msg))
            throw new DescribeException(msg);

        // 清空门店缓存
        redisService.setNullLike(RedisParam.STORE_DATA + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_SERVICE + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_KINDS + storeUid);

        return R.ok();
    }

    @Transactional(rollbackFor = DescribeException.class)
    @ApiOperation(value = "设置订单服务退费")
    @PostMapping(value = "/setOrderRefund", produces = "application/json; charset=UTF-8")
    public R<Object> setOrderRefund(
            HttpServletRequest request,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "会员uid") @RequestParam(value = "memberUid") String memberUid,
            @ApiParam(value = "退费的订单号") @RequestParam(value = "orderCode") String orderCode,
            @ApiParam(value = "退款金额") @RequestParam(value = "orderAmount") Double orderAmount,
            @ApiParam(value = "退款日期 yyyy-MM-dd") @RequestParam(value = "changeDate") String changeDate,
            @ApiParam(value = "结转金额") @RequestParam(value = "carriedForwardAmount") Double carriedForwardAmount,
            @ApiParam(value = "退款服务uid集合 [{uid:'',num:0}]") @RequestParam(value = "serviceJson", required = false) String serviceJson,
            @ApiParam(value = "备注") @RequestParam(value = "orderRemark") String orderRemark
    ) throws Exception {
        R<Object> r = LoginInfoUtil.getLoginDto(request);
        if (R.isError(r)) return r;
        LoginDataDto loginDto = (LoginDataDto) r.getData();

        if (!AccountUtil.isStoreManager(loginDto.getStoreRoles()))
            return R.fail("非店长账号，不能操作");
        if (null == orderAmount || orderAmount <= 0)
            return R.fail("请填写正确的退款金额");
        if (StringUtils.isBlank(changeDate))
            return R.fail("请选择退款日期");
        if (StringUtils.isBlank(orderRemark))
            return R.fail("请填写备注");

        Members members = membersService.getByUid(storeUid, memberUid);
        if (null == members)
            return R.fail("会员获取失败");
        String membersCorpUid = members.getCorpUid();

        Cmorders cmorders = cmordersService.getByOrderCode(storeUid, memberUid, orderCode);
        if (null == cmorders)
            return R.fail("退费的订单获取失败");
        if (null == cmorders.getStatus())
            return R.fail("订单的状态未知，不能操作");
        if (!cmorders.getStatus().equals(1))
            return R.fail("还未审批通过，不能操作");
        // 订单状态 1.正常 2.变更 3.退费 4.已变更 5.已退费 6.已变更/退费
        Integer orderState = cmorders.getOrderState();
        if (null == orderState || (!orderState.equals(EnumType.CmOrderState.OK.getState()) && !orderState.equals(EnumType.CmOrderState.CHANGE.getState())))
            return R.fail("订单不能操作，状态：" + cmorders.getOrderStateName());
        // 是否订金订单
        boolean isEmd = cmorders.getOrderType().equals(EnumType.OrderType.EMD.getType());

        // 退费订单号
        String newRefundOrderCode = KitUtil.getMemberServiceCode();
        if (!isEmd) {
            if (StringUtils.isBlank(serviceJson))
                return R.fail("请先选择要退费的服务");
            JSONArray serviceArray = JSONArray.parseArray(serviceJson);
            if (CollectionUtils.isEmpty(serviceArray))
                return R.fail("请先选择要退费的服务");
            Map<String, Integer> refundNumMap = new HashMap<>();
            for (int i = 0; i < serviceArray.size(); i++) {
                JSONObject jsonObject = serviceArray.getJSONObject(i);
                String uid = jsonObject.getString("uid");
                Integer num = jsonObject.getInteger("num");
                if (StringUtils.isBlank(uid))
                    return R.fail("未传递服务的标识");
                if (num != null && num <= 0)
                    return R.fail("可退数量必须大于0");
                refundNumMap.put(uid, num);
            }

            List<Cmservices> servicesList = cmservicesService.listByOrderCodeAndChangStatusIsNullAndEnding(storeUid, memberUid, orderCode);
            if (CollectionUtils.isEmpty(servicesList))
                return R.fail("订单的服务获取失败");

            List<String> projectUids = new ArrayList<>();
            List<String> serviceUids = new ArrayList<>(refundNumMap.keySet());
            // 选择和未选择的服务
            List<Cmservices> checkServiceList = new ArrayList<>();
            List<Cmservices> unCheckServiceList = new ArrayList<>();
            for (Cmservices service : servicesList) {
                if (serviceUids.contains(service.getUid())) {
                    checkServiceList.add(service);
                } else {
                    unCheckServiceList.add(service);
                }
                projectUids.add(service.getProjectUid());
            }

            // 变更日期
            Date changeDateValue = DateUtil.parseDate(changeDate);
            // 检查服务能否退费
            String judgeRefundServiceMsg = CmorderUtil.judgeRefundServicesV2(checkServiceList, changeDateValue, refundNumMap);
            if (StringUtils.isNotBlank(judgeRefundServiceMsg))
                return R.fail(judgeRefundServiceMsg);

            List<StoreProjects> projectsList = storeProjectsService.listByUids(projectUids);
            if (CollectionUtils.isEmpty(projectsList))
                return R.fail("服务信息获取失败");

            //TODO 开始创建退费订单信息
            List<Cmservices> newConsumeAndRefundAndTransferServiceList = new ArrayList<>();
            List<ServiceStatusLogs> newStatusLogs = new ArrayList<>();
            List<String> checkInvalidServiceUidList = new ArrayList<>();
            List<String> unCheckInvalidServiceUidList = new ArrayList<>();
            List<String> refundServiceUidList = new ArrayList<>();
            List<String> changeServiceUidList = new ArrayList<>();
            // 创建转移的订单状态
            boolean createTransferOrder = false;
            // 创建转移的订单号
            String newTransferOrderCode = KitUtil.getMemberServiceCode();

            // 设置选择退费的服务退费
            for (Cmservices service : checkServiceList) {
                int logStatus = 0;
                if (service.getStatus().equals(pauseCardStatus) || service.getStatus().equals(openCardStatus)) {
                    // 如果服务已开卡，创建消耗服务记录和退费服务记录
                    Integer refundNum = refundNumMap.get(service.getUid());
                    Map<Integer, List<Cmservices>> newServiceMap = CmorderUtil.newConsumeAndRefundServiceListV2(
                            service, staffUid, staffName, storeName, members.getMemberName(),
                            newRefundOrderCode, newTransferOrderCode, changeDateValue,
                            cmorders.getOrderType(), refundNum
                    );
                    List<Cmservices> newConsumeAndRefundList = newServiceMap.get(0);
                    if (CollectionUtils.isNotEmpty(newConsumeAndRefundList))
                        newConsumeAndRefundAndTransferServiceList.addAll(newConsumeAndRefundList);

                    List<Cmservices> newTransferList = newServiceMap.get(1);
                    if (CollectionUtils.isNotEmpty(newTransferList)) {
                        createTransferOrder = true;
                        newConsumeAndRefundAndTransferServiceList.addAll(newTransferList);
                    }
                    checkInvalidServiceUidList.add(service.getUid());
                    logStatus = invalidStatus;
                } else if (service.getStatus().equals(noCardStatus)) {
                    // 如果服务还未开卡，直接退费
                    refundServiceUidList.add(service.getUid());
                    logStatus = refundStatus;
                }
                // 创建服务操作记录
                newStatusLogs.add(CmorderUtil.newStatusLog(service, staffUid, staffName, logStatus, null, null, null));
            }
            // 设置未选择退费的服务变更
            if (CollectionUtils.isNotEmpty(unCheckServiceList)) {
                createTransferOrder = true;
                for (Cmservices service : unCheckServiceList) {
                    int logStatus = 0;
                    if (service.getStatus().equals(pauseCardStatus) || service.getStatus().equals(openCardStatus)) {
                        // 如果已开卡，创建消耗服务记录和变更服务记录
                        List<Cmservices> newServices = CmorderUtil.newConsumeAndChangeServiceListV2(
                                service, staffUid, staffName, storeName, members.getMemberName(), newTransferOrderCode,
                                cmorders.getOrderType(), changeDateValue
                        );
                        newConsumeAndRefundAndTransferServiceList.addAll(newServices);
                        unCheckInvalidServiceUidList.add(service.getUid());
                        logStatus = invalidStatus;
                    } else if (service.getStatus().equals(noCardStatus)) {
                        // 如果服务还未开卡，直接设置已变更
                        changeServiceUidList.add(service.getUid());
                        logStatus = changeStatus;
                    }
                    // 创建服务操作记录
                    newStatusLogs.add(CmorderUtil.newStatusLog(service, staffUid, staffName, logStatus, null, null, null));

                    // 转移结余服务
                    Cmservices transferService = CmorderUtil.copyService(
                            service, changeDateValue, newTransferOrderCode, cmorders.getOrderType(),
                            membersCorpUid, storeUid, storeName, memberUid, members.getMemberName(), staffUid, staffName
                    );
                    if (transferService != null)
                        newConsumeAndRefundAndTransferServiceList.add(transferService);
                }
            }

            // 退费服务设置已变更
            if (CollectionUtils.isNotEmpty(checkInvalidServiceUidList)) {
                boolean b = cmservicesService.updateChangeStatusByUidList(checkInvalidServiceUidList, memberUid, orderCode, staffUid, staffName, newRefundOrderCode, changeDateValue, invalidStatus, invalidName);
                if (!b) throw new DescribeException("服务设置已变更失败");
            }
            // 退费服务设置已退费
            if (CollectionUtils.isNotEmpty(refundServiceUidList)) {
                boolean b = cmservicesService.updateChangeStatusByUidList(refundServiceUidList, memberUid, orderCode, staffUid, staffName, newRefundOrderCode, changeDateValue, refundStatus, refundName);
                if (!b) throw new DescribeException("服务设置已退费失败");
            }
            // 未选择退费的服务设置已变更
            if (CollectionUtils.isNotEmpty(unCheckInvalidServiceUidList)) {
                boolean b = cmservicesService.updateChangeStatusByUidList(unCheckInvalidServiceUidList, memberUid, orderCode, staffUid, staffName, newTransferOrderCode, changeDateValue, invalidStatus, invalidName);
                if (!b) throw new DescribeException("服务设置已变更失败");
            }
            // 未选择退费的服务设置已变更
            if (CollectionUtils.isNotEmpty(changeServiceUidList)) {
                boolean b = cmservicesService.updateChangeStatusByUidList(changeServiceUidList, memberUid, orderCode, staffUid, staffName, newTransferOrderCode, changeDateValue, changeStatus, changeName);
                if (!b) throw new DescribeException("服务设置已变更失败");
            }

            // 创建退费订单
            List<Cmorders> newCmorderList = new ArrayList<>();
            Cmorders newRefundOrder = CmorderUtil.newRefundCmorder(
                    membersCorpUid, storeUid, storeName, staffUid, staffName,
                    memberUid, members.getMemberName(), newRefundOrderCode, orderAmount, changeDateValue, orderRemark, orderCode
            );
            newCmorderList.add(newRefundOrder);
            // 创建结余订单
            Cmorders newTransferOrder = null;
            if (createTransferOrder) {
                newTransferOrder = CmorderUtil.copyCmorder(cmorders, newTransferOrderCode, carriedForwardAmount, orderAmount);
                newCmorderList.add(newTransferOrder);
            }
            cmordersService.saveOrUpdateBatch(newCmorderList);

            // 按订单编号排序
            if (createTransferOrder) {
                List<Cmservices> sortList = newConsumeAndRefundAndTransferServiceList.stream().sorted(Comparator.comparing(Cmservices::getOrderCode)).collect(Collectors.toList());
                cmservicesService.saveOrUpdateBatch(sortList);
            } else {
                cmservicesService.saveOrUpdateBatch(newConsumeAndRefundAndTransferServiceList);
            }
            // 保存服务操作记录
            serviceStatusLogsService.saveBatch(newStatusLogs);


            // 更新原订单的操作人和状态
            boolean l = cmordersService.updateOrderStateAndChangeDate(orderCode, staffUid, staffName,
                    EnumType.CmOrderState.AL_REFUND.getState(), EnumType.CmOrderState.AL_REFUND.getName(), changeDateValue);
            if (!l)
                throw new DescribeException("更新订单退费信息失败");

            // 保存申请记录
            String applyCode = saveApplyLog(
                    2, "退费", membersCorpUid, storeUid, staffUid, staffName, memberUid,
                    orderCode, NepUtil.nullToZero(cmorders.getOrderAmount()), NepUtil.nullToZero(cmorders.getCarriedForwardAmount()),
                    orderAmount, carriedForwardAmount, changeDateValue,
                    orderRemark, createTransferOrder ? newTransferOrderCode : null, newRefundOrderCode, null
            );

            // 创建跟进记录
            saveFollowLog(
                    2, membersCorpUid, storeUid, storeName, staffUid, staffName, memberUid, members.getMemberName(), orderCode,
                    newTransferOrderCode, newRefundOrderCode, applyCode
            );

            // 订单金额拆分
            if (createTransferOrder) {
                String msg = orderAmountSplitUtil.splitServiceAmount(newTransferOrder, newTransferOrder.getCarriedForwardAmount(), null);
                if (StringUtils.isNotBlank(msg))
                    throw new DescribeException(msg);
            }
        } else {
            // 变更日期
            Date changeDateValue = DateUtil.parseDate(changeDate);
            // 创建退费订单
            Cmorders newRefundOrder = CmorderUtil.newRefundCmorder(
                    membersCorpUid, storeUid, storeName, staffUid, staffName,
                    memberUid, members.getMemberName(), newRefundOrderCode, orderAmount, changeDateValue, orderRemark, orderCode
            );
            cmordersService.saveOrUpdate(newRefundOrder);

            // 更新原订单的操作人和状态
            boolean l = cmordersService.updateOrderStateAndChangeDate(orderCode, staffUid, staffName,
                    EnumType.CmOrderState.AL_REFUND.getState(), EnumType.CmOrderState.AL_REFUND.getName(), changeDateValue);
            if (!l)
                throw new DescribeException("更新订单退费信息失败");

            // 保存申请记录
            String applyCode = saveApplyLog(
                    2, "退费", membersCorpUid, storeUid, staffUid, staffName, memberUid,
                    orderCode, NepUtil.nullToZero(cmorders.getOrderAmount()), NepUtil.nullToZero(cmorders.getCarriedForwardAmount()),
                    orderAmount, carriedForwardAmount, changeDateValue,
                    orderRemark, "", newRefundOrderCode, null
            );

            // 创建跟进记录
            saveFollowLog(
                    2, membersCorpUid, storeUid, storeName, staffUid, staffName, memberUid, members.getMemberName(), orderCode,
                    "", newRefundOrderCode, applyCode
            );
        }

        // 清空门店缓存
        redisService.setNullLike(RedisParam.STORE_DATA + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_SERVICE + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_KINDS + storeUid);
        return R.ok();
    }

    @Transactional(rollbackFor = DescribeException.class)
    @ApiOperation(value = "设置订单服务退费")
    @PostMapping(value = "/v2/setOrderRefund", produces = "application/json; charset=UTF-8")
    public R<Object> setOrderRefundV2(
            HttpServletRequest request,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "会员uid") @RequestParam(value = "memberUid") String memberUid,
            @ApiParam(value = "退费的订单号") @RequestParam(value = "orderCode") String orderCode,
            @ApiParam(value = "退款金额") @RequestParam(value = "orderAmount") Double orderAmount,
            @ApiParam(value = "退款日期 yyyy-MM-dd") @RequestParam(value = "changeDate") String changeDate,
            @ApiParam(value = "结转金额") @RequestParam(value = "carriedForwardAmount") Double carriedForwardAmount,
            @ApiParam(value = "退款服务uid集合 [{uid:'',num:0}]") @RequestParam(value = "serviceJson", required = false) String serviceJson,
            @ApiParam(value = "备注") @RequestParam(value = "orderRemark") String orderRemark
    ) throws Exception {
        R<Object> r = LoginInfoUtil.getLoginDto(request);
        if (R.isError(r)) return r;
        LoginDataDto loginDto = (LoginDataDto) r.getData();

        if (!AccountUtil.isStoreManager(loginDto.getStoreRoles()))
            return R.fail("非店长账号，不能操作");
        if (null == orderAmount || orderAmount <= 0)
            return R.fail("请填写正确的退款金额");
        if (StringUtils.isBlank(changeDate))
            return R.fail("请选择退款日期");
        if (StringUtils.isBlank(orderRemark))
            return R.fail("请填写备注");

        Members members = membersService.getByUid(storeUid, memberUid);
        if (null == members)
            return R.fail("会员获取失败");
        String membersCorpUid = members.getCorpUid();

        Cmorders cmorders = cmordersService.getByOrderCode(storeUid, memberUid, orderCode);
        if (null == cmorders)
            return R.fail("退费的订单获取失败");
        if (null == cmorders.getStatus())
            return R.fail("订单的状态未知，不能操作");
        if (!cmorders.getStatus().equals(1))
            return R.fail("还未审批通过，不能操作");
        // 订单状态 1.正常 2.变更 3.退费 4.已变更 5.已退费 6.已变更/退费
        Integer orderState = cmorders.getOrderState();
        if (null == orderState || (!orderState.equals(EnumType.CmOrderState.OK.getState()) && !orderState.equals(EnumType.CmOrderState.CHANGE.getState())))
            return R.fail("订单不能操作，状态：" + cmorders.getOrderStateName());
        // 是否订金订单
        boolean isEmd = cmorders.getOrderType().equals(EnumType.OrderType.EMD.getType());

        // 退费订单号
        String newRefundOrderCode = KitUtil.getMemberServiceCode();
        if (!isEmd) {
            if (StringUtils.isBlank(serviceJson))
                return R.fail("请先选择要退费的服务");
            JSONArray serviceArray = JSONArray.parseArray(serviceJson);
            if (CollectionUtils.isEmpty(serviceArray))
                return R.fail("请先选择要退费的服务");
            Map<String, Integer> refundNumMap = new HashMap<>();
            for (int i = 0; i < serviceArray.size(); i++) {
                JSONObject jsonObject = serviceArray.getJSONObject(i);
                String uid = jsonObject.getString("uid");
                Integer num = jsonObject.getInteger("num");
                if (StringUtils.isBlank(uid))
                    return R.fail("未传递服务的标识");
                if (num != null && num <= 0)
                    return R.fail("可退数量必须大于0");
                refundNumMap.put(uid, num);
            }

            List<Cmservices> servicesList = cmservicesService.listByOrderCodeAndChangStatusIsNullAndEnding(storeUid, memberUid, orderCode);
            if (CollectionUtils.isEmpty(servicesList))
                return R.fail("订单的服务获取失败");

            List<String> projectUids = new ArrayList<>();
            List<String> serviceUids = new ArrayList<>(refundNumMap.keySet());
            // 选择和未选择的服务
            List<Cmservices> checkServiceList = new ArrayList<>();
            List<Cmservices> unCheckServiceList = new ArrayList<>();
            for (Cmservices service : servicesList) {
                if (serviceUids.contains(service.getUid())) {
                    checkServiceList.add(service);
                } else {
                    unCheckServiceList.add(service);
                }
                projectUids.add(service.getProjectUid());
            }

            // 变更日期
            Date changeDateValue = DateUtil.parseDate(changeDate);
            // 检查服务能否退费
            String judgeRefundServiceMsg = CmorderUtil.judgeRefundServicesV2(checkServiceList, changeDateValue, refundNumMap);
            if (StringUtils.isNotBlank(judgeRefundServiceMsg))
                return R.fail(judgeRefundServiceMsg);

            List<StoreProjects> projectsList = storeProjectsService.listByUids(projectUids);
            if (CollectionUtils.isEmpty(projectsList))
                return R.fail("服务信息获取失败");

            //TODO 开始创建退费订单信息
            List<Cmservices> newRefundAndTransferServiceList = new ArrayList<>();
            List<ServiceStatusLogs> newStatusLogs = new ArrayList<>();
            List<String> refundServiceUidList = new ArrayList<>();
            List<String> unRefundServiceUidList = new ArrayList<>();
            // 创建转移的订单状态
            boolean createTransferOrder = false;
            // 创建转移的订单号
            String newTransferOrderCode = KitUtil.getMemberServiceCode();

            // 设置选择退费的服务退费
            for (Cmservices service : checkServiceList) {
                if (service.getStatus().equals(pauseCardStatus) || service.getStatus().equals(openCardStatus) || service.getStatus().equals(noCardStatus)) {
                    // 如果服务已开卡，创建消耗服务记录和退费服务记录
                    Integer refundNum = refundNumMap.get(service.getUid());
                    Map<Integer, List<Cmservices>> newServiceMap = CmorderUtil.newRefundServiceListV3(
                            service, staffUid, staffName, storeName, members.getMemberName(),
                            newRefundOrderCode, newTransferOrderCode, changeDateValue,
                            cmorders.getOrderType(), refundNum
                    );
                    List<Cmservices> newRefundList = newServiceMap.get(0);
                    if (CollectionUtils.isNotEmpty(newRefundList))
                        newRefundAndTransferServiceList.addAll(newRefundList);

                    List<Cmservices> newTransferList = newServiceMap.get(1);
                    if (CollectionUtils.isNotEmpty(newTransferList)) {
                        createTransferOrder = true;
                        newRefundAndTransferServiceList.addAll(newTransferList);
                    }
                    refundServiceUidList.add(service.getUid());
                    // 创建服务操作记录
                    newStatusLogs.add(CmorderUtil.newStatusLog(service, staffUid, staffName, refundStatus, null, null, null));
                }
            }
            // 设置未选择退费的服务变更
            if (CollectionUtils.isNotEmpty(unCheckServiceList)) {
                createTransferOrder = true;
                for (Cmservices service : unCheckServiceList) {
                    if (service.getStatus().equals(pauseCardStatus) || service.getStatus().equals(openCardStatus)) {
                        // 如果已开卡，创建消耗服务记录和变更服务记录
                        List<Cmservices> newServices = CmorderUtil.newChangeServiceListV3(
                                service, staffUid, staffName, storeName, members.getMemberName(), newTransferOrderCode,
                                cmorders.getOrderType(), changeDateValue
                        );
                        if (CollectionUtils.isNotEmpty(newServices))
                            newRefundAndTransferServiceList.addAll(newServices);
                        unRefundServiceUidList.add(service.getUid());
                    } else if (service.getStatus().equals(noCardStatus)) {
                        // 如果服务还未开卡，直接设置已变更
                        unRefundServiceUidList.add(service.getUid());
                    }
                    // 创建服务操作记录
                    newStatusLogs.add(CmorderUtil.newStatusLog(service, staffUid, staffName, changeStatus, null, null, null));

                    // 转移结余服务
                    Cmservices transferService = CmorderUtil.copyService(
                            service, changeDateValue, newTransferOrderCode, cmorders.getOrderType(),
                            membersCorpUid, storeUid, storeName, memberUid, members.getMemberName(), staffUid, staffName
                    );
                    if (transferService != null)
                        newRefundAndTransferServiceList.add(transferService);
                }
            }

            // 退费服务设置已退费
            if (CollectionUtils.isNotEmpty(refundServiceUidList)) {
                boolean b = cmservicesService.updateChangeStatusByUidList(refundServiceUidList, memberUid, orderCode, staffUid, staffName, newRefundOrderCode, changeDateValue, refundStatus, refundName);
                if (!b) throw new DescribeException("服务设置已退费失败");
            }
            // 未选择退费的服务设置已变更
            if (CollectionUtils.isNotEmpty(unRefundServiceUidList)) {
                boolean b = cmservicesService.updateChangeStatusByUidList(unRefundServiceUidList, memberUid, orderCode, staffUid, staffName, newTransferOrderCode, changeDateValue, changeStatus, changeName);
                if (!b) throw new DescribeException("服务设置已变更失败");
            }

            // 创建退费订单
            List<Cmorders> newCmorderList = new ArrayList<>();
            Cmorders newRefundOrder = CmorderUtil.newRefundCmorder(
                    membersCorpUid, storeUid, storeName, staffUid, staffName,
                    memberUid, members.getMemberName(), newRefundOrderCode, orderAmount, changeDateValue, orderRemark, orderCode
            );
            newCmorderList.add(newRefundOrder);
            // 创建结余订单
            Cmorders newTransferOrder = null;
            if (createTransferOrder) {
                newTransferOrder = CmorderUtil.copyCmorder(cmorders, newTransferOrderCode, carriedForwardAmount, orderAmount);
                newCmorderList.add(newTransferOrder);
            }
            cmordersService.saveOrUpdateBatch(newCmorderList);

            // 按订单编号排序
            if (createTransferOrder) {
                List<Cmservices> sortList = newRefundAndTransferServiceList.stream().sorted(Comparator.comparing(Cmservices::getOrderCode)).collect(Collectors.toList());
                cmservicesService.saveOrUpdateBatch(sortList);
            } else {
                cmservicesService.saveOrUpdateBatch(newRefundAndTransferServiceList);
            }
            // 保存服务操作记录
            serviceStatusLogsService.saveBatch(newStatusLogs);


            // 更新原订单的操作人和状态
            boolean l = cmordersService.updateOrderStateAndChangeDate(orderCode, staffUid, staffName,
                    EnumType.CmOrderState.AL_REFUND.getState(), EnumType.CmOrderState.AL_REFUND.getName(), changeDateValue);
            if (!l)
                throw new DescribeException("更新订单退费信息失败");

            // 保存申请记录
            String applyCode = saveApplyLog(
                    2, "退费", membersCorpUid, storeUid, staffUid, staffName, memberUid,
                    orderCode, NepUtil.nullToZero(cmorders.getOrderAmount()), NepUtil.nullToZero(cmorders.getCarriedForwardAmount()),
                    orderAmount, carriedForwardAmount, changeDateValue,
                    orderRemark, createTransferOrder ? newTransferOrderCode : null, newRefundOrderCode, null
            );

            // 创建跟进记录
            saveFollowLog(
                    2, membersCorpUid, storeUid, storeName, staffUid, staffName, memberUid, members.getMemberName(), orderCode,
                    newTransferOrderCode, newRefundOrderCode, applyCode
            );

            // 订单金额拆分
            if (createTransferOrder) {
                String msg = orderAmountSplitUtil.splitServiceAmount(newTransferOrder, newTransferOrder.getCarriedForwardAmount(), null);
                if (StringUtils.isNotBlank(msg))
                    throw new DescribeException(msg);
            }
        } else {
            // 变更日期
            Date changeDateValue = DateUtil.parseDate(changeDate);
            // 创建退费订单
            Cmorders newRefundOrder = CmorderUtil.newRefundCmorder(
                    membersCorpUid, storeUid, storeName, staffUid, staffName,
                    memberUid, members.getMemberName(), newRefundOrderCode, orderAmount, changeDateValue, orderRemark, orderCode
            );
            cmordersService.saveOrUpdate(newRefundOrder);

            // 更新原订单的操作人和状态
            boolean l = cmordersService.updateOrderStateAndChangeDate(orderCode, staffUid, staffName,
                    EnumType.CmOrderState.AL_REFUND.getState(), EnumType.CmOrderState.AL_REFUND.getName(), changeDateValue);
            if (!l)
                throw new DescribeException("更新订单退费信息失败");

            // 保存申请记录
            String applyCode = saveApplyLog(
                    2, "退费", membersCorpUid, storeUid, staffUid, staffName, memberUid,
                    orderCode, NepUtil.nullToZero(cmorders.getOrderAmount()), NepUtil.nullToZero(cmorders.getCarriedForwardAmount()),
                    orderAmount, carriedForwardAmount, changeDateValue,
                    orderRemark, "", newRefundOrderCode, null
            );

            // 创建跟进记录
            saveFollowLog(
                    2, membersCorpUid, storeUid, storeName, staffUid, staffName, memberUid, members.getMemberName(), orderCode,
                    "", newRefundOrderCode, applyCode
            );
        }

        // 清空门店缓存
        redisService.setNullLike(RedisParam.STORE_DATA + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_SERVICE + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_KINDS + storeUid);
        return R.ok();
    }


    @ApiOperation(value = "获取关联订单的信息")
    @PostMapping(value = "/getRelationOrders")
    public R<Object> getRelationOrders(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "订单编号") @RequestParam(value = "orderCode") String orderCode
    ) {
        Cmorders data = cmordersService.getByOrderCode(null, null, orderCode);
        if (null == data)
            return R.fail("订单信息获取失败");

        List<CmorderDto> list = new ArrayList<>();
        if (null != data.getOrderState() && !data.getOrderState().equals(1)) {
            list = cmordersService.listByOrderCodeAndRelationCode(storeUid, orderCode, data.getRelationCode());
            if (CollectionUtils.isNotEmpty(list))
                CmorderUtil.getServiceListByOrderCode(storeUid, list);
        }

        return R.ok(list);
    }


    @ApiOperation(value = "审批会员订单")
    @PostMapping(value = "/updateStatus", produces = "application/json; charset=UTF-8")
    public R<Object> updateStatus(
            HttpServletRequest request,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "服务订单编号") @RequestParam(value = "orderCode") String orderCode,
            @ApiParam(value = "财务审批状态 1.审批通过 -1.审批拒绝") @RequestParam(value = "status") Integer status,
            @ApiParam(value = "审批备注") @RequestParam(value = "remark", required = false) String remark
    ) {
        R<Object> r = LoginInfoUtil.getLoginDto(request);
        if (R.isError(r)) return r;
        LoginDataDto loginDto = (LoginDataDto) r.getData();

        if (status.equals(-1) && com.alibaba.excel.util.StringUtils.isBlank(remark))
            return R.fail("请填写审批备注");

        Cmorders data = cmordersService.getByOrderCode(null, null, orderCode);
        if (null == data)
            return R.fail("会员订单获取失败");
        if (AccountUtil.isSelfStore(loginDto.getCurrentOperationType()))
            return R.fail("非加盟店，不能操作");
        if (!AccountUtil.isStoreManager(loginDto.getStoreRoles()))
            return R.fail("非店长账号，不能操作");
        if (data.getStatus().equals(status))
            return R.fail(data.getStatusName() + "，不能操作");
        if (data.getStatus().equals(1)) {
            OrderStatusLogs log = orderStatusLogsService.getByOrderCode(orderCode);
            if (log != null && TimeUtil.moreThanDay(log.getAddTime(), 30))
                return R.fail("审批通过已超过30天，不能操作");
        }

        String statusName = "";
        if (status.equals(1))
            statusName = "审批通过";
        else if (status.equals(-1))
            statusName = "审批拒绝";
        else
            return R.fail("审批状态错误");

        boolean l = cmordersService.updateStatus(orderCode, status, statusName, staffUid, staffName, remark);
        if (!l)
            return R.fail("审批失败");

        OrderStatusLogs logs = new OrderStatusLogs();
        logs.setCorpUid(data.getCorpUid());
        logs.setStoreUid(data.getStoreUid());
        logs.setOrderCode(orderCode);
        logs.setStatus(status);
        logs.setStatusName(statusName);
        logs.setRemark(remark);
        logs.setOpStaffUid(staffUid);
        logs.setOpStaffFullName(staffName);
        orderStatusLogsService.saveOrUpdate(logs);

        // 跟进记录
        String followType = EnumType.Follow.AUDIT_ORDER.getType();
        String followTypeName = EnumType.Follow.AUDIT_ORDER.getName();
        String content = StringUtils.isBlank(remark) ? "订单编号： " + orderCode + "，" + statusName :
                "订单编号： " + orderCode + "，" + statusName + "；备注：" + remark;
        MemberFollow follow = FollowUtil.newFollow(
                data.getCorpUid(), storeUid, storeName, staffUid, staffName,
                data.getMemberUid(), data.getMemberName(), followType, followTypeName, content,
                orderCode, DateUtil.getNowDatetime()
        );
        memberFollowService.saveOrUpdate(follow);

        return R.ok();
    }

    @ApiOperation(value = "获取创建会员订单的数据")
    @PostMapping(value = "/getCreateCmorderData", produces = "application/json; charset=UTF-8")
    public R<Object> getCreateCmorderData(
            HttpServletRequest request,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName
    ) {
        R<Object> r = LoginInfoUtil.getLoginDto(request);
        if (R.isError(r)) return r;
        LoginDataDto loginDto = (LoginDataDto) r.getData();

        List<Integer> cooperationTypes = loginDto.getCurrentCooperationTypes();
        Integer operationType = loginDto.getCurrentOperationType();

        String cooperationTypeSql = AccountUtil.getCooperationTypeSql(cooperationTypes);
        String operationTypeSql = AccountUtil.getOperationTypeSql(operationType);

        JSONObject jsonObject = new JSONObject();
        // 获取签单人信息
        List<JSONObject> staffList = staffService.listByStoreStaff(storeUid, 1, "", null);
        jsonObject.put("staffList", staffList);

        // 获取服务和周期信息
        // redis取值
        String redisKey = RedisParam.PROJECT_CYCLE + storeUid;
        String json = (String) redisService.get(redisKey);
        if (StringUtils.isNotBlank(json)) {
            List<StoreProjectsDtoV2> list = JSONArray.parseArray(json, StoreProjectsDtoV2.class);
            jsonObject.put("projectAndCycleList", list);
        } else {
            boolean selfStore = AccountUtil.isSelfStore(loginDto.getCurrentOperationType());

            // 获取门店的服务
            List<Long> projectIdList = storesService.getProjectIdList(storeUid);
            if (CollectionUtils.isEmpty(projectIdList))
                return R.fail("门店未分配服务，请联系运营人员");
            List<StoreProjectsDtoV2> list = projectsService.dtoListByStoreUidAndSelfStoreV5(
                    storeUid, null, null, null, projectIdList
            );


            // 设置周期并禁用没有周期的服务
            List<StoreProjectsDtoV2> newList = CmorderUtil.setCycleList(selfStore, storeUid, list);
            jsonObject.put("projectAndCycleList", newList);
            // redis缓存
            redisService.set(redisKey, JsonUtil.toJsonString(newList), RedisParam.MINUTE_TIME);
        }

        // 获取产品包信息
        List<StoreProductDto> productsList = storeProductsService.getDtoListV2(storeUid, cooperationTypeSql, operationTypeSql);
        if (CollectionUtils.isNotEmpty(productsList)) {
            List<String> uidList = productsList.stream().map(StoreProductDto::getUid).collect(Collectors.toList());

            List<StoreProductLogDto> logs = productLogsService.dtoListByProductUidIn(uidList);
            Map<String, List<StoreProductLogDto>> logMap = null;
            if (CollectionUtils.isNotEmpty(logs)) {
                logMap = logs.stream().collect(Collectors.groupingBy(StoreProductLogDto::getProductUid));
            }
            if (logMap != null) {
                for (StoreProductDto products : productsList) {
                    String uid = products.getUid();
                    List<StoreProductLogDto> logsList = logMap.get(uid);
                    products.setList(logsList);
                }
            }
        }
        jsonObject.put("productList", productsList);

        return R.ok(jsonObject);
    }


    @ApiOperation(value = "导出会员订单")
    @PostMapping(value = "/exportList", produces = "application/vnd.ms-excel;charset=UTF-8")
    public void exportList(
            HttpServletRequest request,
            HttpServletResponse response,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "订单号/会员姓名/合同号") @RequestParam(value = "keyword", required = false) String keyword,
            @ApiParam(value = "收入类型") @RequestParam(value = "orderType", required = false) String orderType,
            @ApiParam(value = "收款开始日期") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "收款结束日期") @RequestParam(value = "endDate", required = false) String endDate,
            @ApiParam(value = "财务审批状态 0.待审批 1.通过 -1.退回") @RequestParam(value = "status", required = false) Integer status
    ) throws Exception {
        // 获取员工信息
        R<Object> r = LoginInfoUtil.getLoginDto(request);
        if (R.isError(r))
            throw new DescribeException(500, r.getMsg());

        LoginDataDto loginDto = (LoginDataDto) r.getData();
        if (!AccountUtil.isStoreManager(loginDto.getStoreRoles()))
            throw new DescribeException("非店长账号，不能操作");

        if (StringUtils.isBlank(beginDate) || StringUtils.isBlank(endDate))
            throw new DescribeException("请选择开始和结束日期");
        Date bDate = DateUtil.parseDate(beginDate);
        Date eDate = DateUtil.parseDate(endDate);
        long days = DateUtil.differentDays(bDate, eDate);
        if (days > 366)
            throw new DescribeException("开始日期和结束日期不能超过一年");

        List<Cmorders> list = cmordersService.exportList(storeUid, keyword, orderType, status, beginDate, endDate);
        if (CollectionUtils.isEmpty(list))
            throw new DescribeException(beginDate + "至" + endDate + "，未查询到信息");

        List<String> orderCodeList = list.stream().map(Cmorders::getOrderCode).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        List<CmservicesDto> serviceList = cmservicesService.dtoListByOrderCodesAndStatusIn(storeUid, orderCodeList);
        Map<String, List<CmservicesDto>> serviceMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(serviceList))
            serviceMap = serviceList.stream().collect(Collectors.groupingBy(CmservicesDto::getOrderCode));

        // 表格头部列的数据
        List<List<String>> headList = new ArrayList<>();
        // 表格第一列默认是门店名称
        headList.add(Collections.singletonList("订单号"));
        headList.add(Collections.singletonList("订单状态"));
        headList.add(Collections.singletonList("会员名称"));
        headList.add(Collections.singletonList("收款日期"));
        headList.add(Collections.singletonList("收入类型"));
        headList.add(Collections.singletonList("收款金额"));
        headList.add(Collections.singletonList("签单人"));
        headList.add(Collections.singletonList("礼品领取"));
        headList.add(Collections.singletonList("礼品备注"));
        headList.add(Collections.singletonList("订单服务"));
        headList.add(Collections.singletonList("备注"));
        headList.add(Collections.singletonList("审批状态"));
        // 表格内的数据
        List<List<Object>> dataList = new ArrayList<>();

        for (Cmorders cmorders : list) {
            List<Object> data = new ArrayList<>();
            data.add(cmorders.getOrderCode());
            data.add(cmorders.getOrderStateName());
            data.add(cmorders.getMemberName());
            if (cmorders.getOrderDate() != null)
                data.add(DateUtil.getDefaultTime2DateStr(cmorders.getOrderDate()));
            else
                data.add("");
            data.add(EnumType.OrderType.getName(cmorders.getOrderType()));
            data.add(cmorders.getOrderAmount());
            data.add(cmorders.getSaleStaffFullName());
            if (cmorders.getGiftGotten() != null)
                data.add(cmorders.getGiftGotten().equals("1") ? "领取" : "未领取");
            else
                data.add("");
            data.add(NepUtil.nullToZero(cmorders.getGiftRemark()));

            String serviceInfo = "";
            List<CmservicesDto> cmservices = serviceMap.get(cmorders.getOrderCode());
            if (CollectionUtils.isNotEmpty(cmservices))
                serviceInfo = cmservices.stream().map(
                        service -> {
                            String msg = CmorderUtil.getProductName(service);
                            if (service.getBeginDate() != null && service.getEndDate() != null) {
                                String bgn = DateUtil.getDefaultTime2DateStr(service.getBeginDate());
                                String end = DateUtil.getDefaultTime2DateStr(service.getEndDate());
                                msg += " " + bgn + "至" + end;
                            }
                            return msg + "\n";
                        }
                ).collect(Collectors.joining(" "));
            data.add(serviceInfo);

            data.add(NepUtil.nullToZero(cmorders.getOrderRemark()));
            data.add(cmorders.getStatusName());

            dataList.add(data);
        }

        String fileName = "会员服务订单" + beginDate + "至" + endDate;
        EasyExcel.write(ExcelHandler.getOutputStream(fileName, response))
                // 设置单元格样式
                .registerWriteHandler(ExcelHandler.getCellStyleStrategy())
                .head(headList)
                .sheet("会员服务订单")
                .doWrite(dataList);
    }


    @ApiOperation(value = "查询手机号是否有订单")
    @PostMapping(value = "/searchOrderByPhone", produces = "application/json;charset=UTF-8")
    public R<Object> searchOrderByPhone(
            @ApiParam(value = "手机号码文本") @RequestParam(value = "phoneText") List<String> phoneText
    ) throws Exception {
        if (CollectionUtils.isEmpty(phoneText))
            return R.fail("请先传递手机号码");

        List<String> searchPhoneList = phoneText.stream().filter(s -> StringUtils.isNotBlank(s) && s.length() == 11).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(searchPhoneList))
            return R.fail("手机号码信息解析后，发现手机号码格式错误");

        List<Members> membersList = membersService.listByPhoneList(searchPhoneList);
        if (CollectionUtils.isEmpty(membersList)) {
            List<SearchMemberDto> list = new ArrayList<>();
            for (String phone : phoneText) {
                list.add(new SearchMemberDto(phone, "未注册", 1));
            }
            return R.ok(list);
        }

        // 会员手机号分组
        List<String> memberUidList = membersList.stream().map(Members::getUid).collect(Collectors.toList());
        List<Cmorders> cmordersList = cmordersService.listByMemberUidInAndOrderDate(memberUidList, "2025-08-15");
        if (CollectionUtils.isEmpty(cmordersList)) {
            List<SearchMemberDto> list = new ArrayList<>();
            for (String phone : phoneText) {
                list.add(new SearchMemberDto(phone, "无订单", 1));
            }
            return R.ok(list);
        }

        // 会员手机号码分组
        Map<String, List<Members>> memberMap = membersList.stream().collect(Collectors.groupingBy(Members::getMob));
        // 服务会员uid分组
        List<String> orderCodeList = cmordersList.stream().map(Cmorders::getOrderCode).collect(Collectors.toList());
        List<Cmservices> cmservicesList = cmservicesService.listByOrderCodeIn(orderCodeList);
        Map<String, Set<String>> serviceMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(cmservicesList)) {
            serviceMap = cmservicesList.stream().collect(Collectors.groupingBy(Cmservices::getMemberUid, Collectors.mapping(Cmservices::getProductName, Collectors.toSet())));
        }

        List<SearchMemberDto> list = new ArrayList<>();
        for (String phone : phoneText) {
            if (phone.length() != 11) {
                list.add(new SearchMemberDto(phone, "手机号码错误", 0));
                continue;
            }
            List<Members> members = memberMap.get(phone);
            if (CollectionUtils.isEmpty(members)) {
                list.add(new SearchMemberDto(phone, "未注册", 1));
                continue;
            }
            Set<String> projectNameList = new HashSet<>();
            for (Members member : members) {
                Set<String> serviceList = serviceMap.get(member.getUid());
                if (CollectionUtils.isNotEmpty(serviceList)) {
                    projectNameList.addAll(serviceList);
                }
            }
            if (CollectionUtils.isNotEmpty(projectNameList)) {
                Set<String> nameList = new HashSet<>();
                for (String projectName : projectNameList) {
                    if (projectName.contains("wk") || projectName.contains("WK") || projectName.contains("jt") || projectName.contains("JT")) {
                        nameList.add("英文");
                    } else {
                        nameList.add("中文");
                    }
                }
                String nameStr = StringUtils.join(nameList, "+");
                list.add(new SearchMemberDto(phone, "老会员，" + nameStr, 0));
            } else {
                list.add(new SearchMemberDto(phone, "无订单", 1));
            }
        }
        return R.ok(list);
    }

    /**
     * 创建或更新服务信息
     */
    private String dealServiceList(
            String corpUid, String storeUid, String storeName, String staffUid, String staffName,
            List<Cmservices> serviceList, Map<String, StoreProjects> projectMap,
            Map<String, StoreProducts> productMap, Map<String, StoreProductLogs> productLogMap,
            String memberUid, String memberName, String orderCode, String orderType, boolean isEmd
    ) {
        if (isEmd) {
            // 是订金则删除全部服务
            cmservicesService.dropByOrderCode(storeUid, memberUid, orderCode);
        } else {
            List<String> updateServiceUids = new ArrayList<>();
            List<Cmservices> newServiceList = new ArrayList<>();
            for (Cmservices service : serviceList) {
                if (StringUtils.isBlank(service.getUid())) {
                    String projectUid = service.getProjectUid();
                    String productUid = service.getProductUid();
                    String productLogUid = service.getProductLogUid();

                    StoreProjects projects = projectMap.get(projectUid);
                    if (null == projects)
                        return "基础服务获取失败";
                    Long projectsId = projects.getId();
                    String projectName = projects.getProjectName();
                    Integer lessonStatus = projects.getLessonStatus();
                    Integer freeStatus = projects.getFreeStatus();
                    if (CmorderUtil.isConsumeLesson(lessonStatus, freeStatus)) {
                        Integer totalLessons = service.getTotalLessons();
                        if (null == totalLessons || totalLessons <= 0)
                            return "请填写正确的活动次数";
                    }

                    StoreProducts products = null;
                    String productName = null;
                    Integer productType = null;
                    if (null != productMap && StringUtils.isNotBlank(productUid)) {
                        products = productMap.get(productUid);
                        if (null == products)
                            return "产品包获取失败";
                        productName = products.getProductName();
                        productType = products.getProductType();
                    }

                    StoreProductLogs productLogs = null;
                    String productLogsName = null;
                    if (null != productLogMap && StringUtils.isNotBlank(productLogUid)) {
                        productLogs = productLogMap.get(productLogUid);
                        if (null == productLogs)
                            return "产品记录获取失败";
                        productLogsName = productLogs.getName();
                    }

                    CmorderUtil.newService(service, orderCode, orderType, corpUid, storeUid, storeName,
                            memberUid, memberName, staffUid, staffName,
                            projectsId, projectName, lessonStatus, freeStatus, productName, productLogsName, productType);
                    newServiceList.add(service);
                } else {
                    updateServiceUids.add(service.getUid());
                }
            }

            // 删除时判断是否包括已开卡的服务
            boolean deleteOpenServices = cmservicesService.existOpenServices(storeUid, memberUid, orderCode, updateServiceUids);
            if (deleteOpenServices)
                return "已开卡的基础服务或产品包服务不能删除";

            // 删除不要的且未开卡的基础服务
            cmservicesService.dropByOrderCodeAndUidNot(storeUid, memberUid, orderCode, updateServiceUids);
            // 保存新数据
            if (CollectionUtils.isNotEmpty(newServiceList))
                cmservicesService.saveOrUpdateBatch(newServiceList);
            // 最后更新数据
            if (CollectionUtils.isNotEmpty(updateServiceUids))
                cmservicesService.updateList(storeUid, memberUid, orderCode, orderType, updateServiceUids, staffUid, staffName);
        }
        return "";
    }

    /**
     * 创建或更新付款图片
     */
    private void dealPayPicList(List<Cmpaypics> payPicList, String orderCode, String staffUid) {
        if (CollectionUtils.isEmpty(payPicList)) {
            // 删除订单的所有付款截图
            List<String> urlList = cmpaypicsService.urlListByOrderCode(orderCode);
            if (CollectionUtils.isNotEmpty(urlList)) {
                cmpaypicsService.dropByOrderCode(orderCode);
                LocalFileUtil.deleteImgList(LocalFileUtil.payImgBaseDir, urlList);
            }
        } else {
            List<Cmpaypics> newPayPicList = new ArrayList<>();
            List<Long> ids = new ArrayList<>();
            for (Cmpaypics pic : payPicList) {
                if (null == pic.getId() || pic.getId() <= 0) {
                    pic.setOrderCode(orderCode);
                    pic.setStaffUid(staffUid);
                    newPayPicList.add(pic);
                } else {
                    ids.add(pic.getId());
                }
            }
            // 先删除不要的数据
            List<String> urlList = cmpaypicsService.urlListByOrderCodeAndIdNot(orderCode, ids);
            if (CollectionUtils.isNotEmpty(urlList)) {
                cmpaypicsService.dropByOrderCodeAndIdNot(orderCode, ids);
                LocalFileUtil.deleteImgList(LocalFileUtil.payImgBaseDir, urlList);
            }
            // 再保存新数据
            if (CollectionUtils.isNotEmpty(newPayPicList))
                cmpaypicsService.saveOrUpdateBatch(newPayPicList);
        }
    }

    /**
     * 验证签单人信息
     */
    private String judgeSaleStaff(Staff saleStaff) {
        if (null == saleStaff)
            return "签单人获取失败";
        if (StringUtils.isBlank(saleStaff.getFullName()))
            return "请先完善签单人的全名";
        if (StringUtils.isBlank(saleStaff.getPriPhone()))
            return "请先完善签单人的私人电话";
        return "";
    }

    /**
     * 验证订单能否更新
     */
    private String judgeUpdateCmorder(Cmorders data, List<LoginDataDto.StoreRolesBean> storeRoles, String orderRemark) {
        if (null == data)
            return "订单获取失败";

        // 自营门店且财务审批通过，不能编辑或删除
        if (data.getStatus() != null && data.getStatus().equals(1))
            return "审批已通过，不能操作";

        Integer orderState = data.getOrderState();
        if (orderState != null && !orderState.equals(EnumType.CmOrderState.OK.getState()) && !orderState.equals(EnumType.CmOrderState.CHANGE.getState()))
            return "订单不能操作，状态：" + data.getOrderStateName();

        if (TimeUtil.moreThanDay(data.getAddTime(), 5)) {
            if (AccountUtil.isStoreManager(storeRoles)) {
                if (StringUtils.isBlank(orderRemark))
                    return "请在备注填写修改原因";
                // 店长超过半年，不能操作
                if (TimeUtil.moreThanDay(data.getAddTime(), 180))
                    return "订单提交超过半年，不能操作";
            } else {
                // 非店长超过5天，不能操作
                return "订单提交超过5天，不能操作";
            }
        }

        return "";
    }

    /**
     * 保存申请记录
     */
    private String saveApplyLog(
            int type, String typeName, String corpUid, String storeUid, String staffUid, String staffName, String memberUid,
            String orderCode, double orderAmount, double carriedForwardAmount, double applyAmount, double unconsumedAmount,
            Date changDate, String remark, String newChangeOrderCode, String newRefundOrderCode, List<Cmpaypics> pics
    ) {
        String applyCode = KitUtil.getCmorderApplyCode();
        CmorderApply apply = new CmorderApply();
        apply.setCorpUid(corpUid);
        apply.setStoreUid(storeUid);
        apply.setMemberUid(memberUid);
        apply.setAddStaffUid(staffUid);
        apply.setAddStaffName(staffName);
        apply.setLastStaffUid(staffUid);
        apply.setLastStaffName(staffName);
        apply.setApplyCode(applyCode);
        apply.setType(type);
        apply.setTypeName(typeName);
        apply.setOrderCode(orderCode);
        apply.setOrderAmount(orderAmount);
        apply.setCarryidAmount(carriedForwardAmount);
        apply.setChangeDate(changDate);
        if (type == 1) {
            double totalAmount = DoubleUtil.sum(orderAmount, carriedForwardAmount);
            double sub = DoubleUtil.sub(totalAmount, unconsumedAmount);
            apply.setConsumedAmount(sub);
            apply.setUnconsumedAmount(unconsumedAmount);
        } else {
            double sum = DoubleUtil.sum(orderAmount, carriedForwardAmount);
            double sub = DoubleUtil.sub(sum, unconsumedAmount);
            apply.setConsumedAmount(sub);
            apply.setUnconsumedAmount(unconsumedAmount);
            if (applyAmount > 0)
                applyAmount = -applyAmount;
        }
        apply.setApplyAmount(applyAmount);
        apply.setRemark(remark);
        cmorderApplyService.saveOrUpdate(apply);
        // 保存申请关联的服务
        List<CmorderApplyLog> newLogList = new ArrayList<>();
        CmorderApplyLog applyLog = saveApplyLog(corpUid, storeUid, staffUid, staffName, applyCode, orderCode);
        newLogList.add(applyLog);
        if (StringUtils.isNotBlank(newChangeOrderCode)) {
            CmorderApplyLog changeLog = saveApplyLog(corpUid, storeUid, staffUid, staffName, applyCode, newChangeOrderCode);
            newLogList.add(changeLog);
        }
        if (StringUtils.isNotBlank(newRefundOrderCode)) {
            CmorderApplyLog refundLog = saveApplyLog(corpUid, storeUid, staffUid, staffName, applyCode, newRefundOrderCode);
            newLogList.add(refundLog);
        }
        cmorderApplyLogService.saveOrUpdateBatch(newLogList);
        // 保存申请付款的图片
        if (CollectionUtils.isNotEmpty(pics)) {
            List<CmorderApplyImg> newImgList = new ArrayList<>();
            for (Cmpaypics pic : pics) {
                CmorderApplyImg applyImg = new CmorderApplyImg();
                applyImg.setCorpUid(corpUid);
                applyImg.setStoreUid(storeUid);
                applyImg.setAddStaffUid(staffUid);
                applyImg.setAddStaffName(staffName);
                applyImg.setApplyCode(applyCode);
                applyImg.setImgUrl(pic.getImgUrl());
                newImgList.add(applyImg);
            }
            cmorderApplyImgService.saveOrUpdateBatch(newImgList);
        }

        return applyCode;
    }

    /**
     * 创建申请记录关联的订单号
     */
    private CmorderApplyLog saveApplyLog(String corpUid, String storeUid, String staffUid, String staffName, String applyCode, String orderCode) {
        CmorderApplyLog applyLog = new CmorderApplyLog();
        applyLog.setCorpUid(corpUid);
        applyLog.setStoreUid(storeUid);
        applyLog.setAddStaffUid(staffUid);
        applyLog.setAddStaffName(staffName);
        applyLog.setApplyCode(applyCode);
        applyLog.setOrderCode(orderCode);
        return applyLog;
    }

    /**
     * 创建跟进记录
     */
    private void saveFollowLog(
            int type, String corpUid, String storeUid, String storeName, String staffUid, String staffName,
            String memberUid, String memberName, String orderCode, String newChangeOrderCode, String newRefundOrderCode,
            String applyCode
    ) {
        Date followTime = DateUtil.getNowDatetime();
        // 创建跟进记录
        if (type == 1) {
            // 创建跟进记录
            String content = orderCode + "申请变更，创建变更订单：" + newChangeOrderCode + "；申请单号：" + applyCode;
            MemberFollow follow = FollowUtil.newFollow(
                    corpUid, storeUid, storeName, staffUid, staffName, memberUid, memberName,
                    EnumType.Follow.NEW_CHANGE_ORDER.getType(), EnumType.Follow.NEW_CHANGE_ORDER.getName(),
                    content, orderCode, followTime
            );
            memberFollowService.saveOrUpdate(follow);
        } else {
            String content = orderCode + "申请退费，创建退费订单：" + newRefundOrderCode;
            if (StringUtils.isNotBlank(newChangeOrderCode))
                content += "，将结余或未选择退费的服务转移至新订单：" + newChangeOrderCode;
            content += "；申请单号：" + applyCode;
            MemberFollow follow = FollowUtil.newFollow(
                    corpUid, storeUid, storeName, staffUid, staffName, memberUid, memberName,
                    EnumType.Follow.NEW_REFUND_ORDER.getType(), EnumType.Follow.NEW_REFUND_ORDER.getName(),
                    content, newRefundOrderCode, followTime
            );
            memberFollowService.saveOrUpdate(follow);
        }
    }

}
